/** ***********************************************************************************
* @file         gnss_task.c
* @brief        GNSS数据基础管理任务
* @details      主要用来处理GNSS基础服务数据，输出数据接口；
* @author       杨小珛
* @date         2020/12/30
* @copyright    北京高知科技有限公司    
* @version      V1.0
* @attention    无
**************************************************************************************/
#include <math.h>
#include <string.h>
#include <stdlib.h>

#include "gnss_task.h"
#include "com_lib.h"
#include "log_task.h"
#include "rtc_task.h"
#include "mon_task.h"
#include "power_task.h"
#if GNSS_QXWZ
#include "qxwz_service.h"
#endif
#include "net_port.h"
#include "flash_buffer.h"
#include "flash_config.h"
#include "agnss_task.h"
#include "event_task.h"
#include "lbs_task.h"
//#include "lbs_task.h"

#define GNSS_GPDRC_DATA_LEN ( 1024 )
#define GNSS_GPDRC4_DATA_LEN ( 1024 )
#define NMEA_TYPE_LEN   ( 24 )
const char *nmea_pheads[] = { "$GNGGA","$GPGGA","$BDGGA","$GNGSA","$GPGSA","$BDGSA","$GNRMC","$GPRMC","$BDRMC","$GNTXT","$GPTXT","$BDTXT","$GNGSV","$GPGSV","$BDGSV","$GNVTG","$GPVTG","$BDVTG","$GNGLL","$GPGLL","$BDGLL","$GNZDA","$GPZDA","$BDZDA"};

GaozMutexHandle_t   gnss_info_mutex; /*GNSS 信息互斥体*/
//GaozSemaphoreHandle_t gnss_reveive_semaphore; /*GNSS数据接收信号量*/
GaozMutexHandle_t gnss_rev_data_mutex; 
GaozQueueHandle_t gnss_recv_data_queue; /*定义网络发送数据消息队列*/

#define GNSS_INVALID_TIEER  ( 60 * GAOZ_TICK_PERIOD_S )        /*定位后1分钟内没有数据时就会自动断开*/
#define GNSS_NO_DATA_TIEER  ( 60 * GAOZ_TICK_PERIOD_S )         /*定位模块打开后1分钟后没有数据重新启动*/
#define GNSS_INVALID_LOC_TIEER (15 * 60 * GAOZ_TICK_PERIOD_S  )    /*定位模块打开后3分钟内没有产生定位需要重新启动模块*/

#define gnss_info_mutex_take()  gaoz_mutex_lock(gnss_info_mutex)  //占有gnss_info_mutex
#define gnss_info_mutex_give()  gaoz_mutex_unlock(gnss_info_mutex)//释放gnss_info_mutex


typedef struct
{
    uint8_t valid_total_num_sat;    // 有效的可见卫星总数（00 - 30）
    uint8_t snr_avr;                // 平均载噪比
    uint32_t total_snr;             // 载噪比之和
} gnss_sat_user_info_t;

// 可见卫星信息结构体
typedef struct
{
    uint8_t sat_id;            // 卫星标识号
    uint8_t sat_elev;          // 卫星仰角（00 - 90）度
    uint16_t sat_az;           // 卫星方位角（00 - 359）度
    uint8_t sat_cn0;           // 载噪比
} gnss_sat_base_info_t;

// GPGSV数据结构体(可见卫星信息)
typedef struct
{
    uint8_t total_num_sen;                  // 本次GSV语句的总数目（1 - 9）
    uint8_t sen_num;                        // 本条GSV语句是本次GSV语句的第几条（1 - total_num_sen）
    uint8_t total_num_sat;                  // 当前可见卫星总数（00 - 32）
    gnss_sat_base_info_t sat_info[32];      // 卫星信息  最大为32条
    gnss_sat_user_info_t sat_user_info;     // 应用层的卫星信息
} gnss_gsv_info_t;


static gnss_info_struct gnss_info_now;
static gnss_info_struct gnss_info_old;  

static gnss_recv_buf_typedef gnss_recv_data;    /*GNSS数据接收底层缓存数据*/
static gnss_recv_buf_typedef gnss_nmea_data;    /*定义GNSS数据接收的NMEA的空间地址，数据长度为GNSS_NMEA_DATA_LEN*/

static uint32_t gnss_invalid_speed_count;       /*GNSS 无效定位速度数据计数器*/
static uint32_t gnss_valid_speed_count;         /*GNSS 有效效定位速度数据计数器*/

static uint32_t gnss_invalid_time;              /*GNSS 无效定位时间计数器*/ 
static uint32_t gnss_invalid_data_time;         /*GNSS 任务无定位数据时间计数器*/
static uint32_t gnss_invalid_location_time;     /*GNSS 无效定位錝hi就*/
static uint32_t gnss_data_save_location;        /*GNSS数据保存的位置*/
uint8_t gnss_reset = 0;

static uint32_t gnss_set_time_tick;
static uint8_t  gnss_power_man_id;
static uint8_t  gnss_set_time_zone;

static uint32_t gnss_driving_mileage;           /*GNSS 累积行驶的里程*/
static uint32_t gnss_driving_latitude;
static uint32_t gnss_driving_longitude;

static uint32_t gnss_static_filter_count;                               /*GNSS 静态过滤次数*/
static gnss_static_filter_buf_t gnss_static_filter_buf;                 /*GNSS 静态缓存数据空间*/
static gnss_static_filter_enable_state_e gnss_static_filter_enable_st;  /*GNSS 静止数据过滤使能状态*/
static uint8_t gnss_gpdrc_data_buf[GNSS_GPDRC_DATA_LEN];                /*GNSS GPDRC数据缓存空间*/
static uint8_t gnss_gpdrc4_data_buf[GNSS_GPDRC_DATA_LEN];               /*GNSS GPDRC数据缓存空间*/
static gnss_qxsdk_enable_state_e gnss_qxsdk_enable_st;                  /*千寻SDK使能标志*/
static uint8_t gnss_lbs_position_type;        
static uint8_t gnss_lbs_position_once_state;        
uint8_t gnss_lbs_position_new_state;    

static void gnss_data_handle_task( void * pvParameters );

static uint32_t gnss_data_info_parse( uint8_t *pSrc, uint16_t wLen );
static uint32_t gnss_data_parse_rmc( gnss_info_struct * pGps, uint8_t *pSrc, uint16_t bLen );
static uint32_t gnss_data_parse_gga( gnss_info_struct * pGps, uint8_t *pSrc, uint16_t bLen );
static uint32_t gnss_data_parse_gsa( gnss_info_struct * pGps, uint8_t *pSrc, uint16_t bLen );
#if( OS_GNSS_MODULE_TYPE == 1 ) /*选择GNSS型号为中科微，通信波特率为115200*/
static uint32_t gnss_data_parse_txt( gnss_info_struct * pGps, uint8_t *pSrc, uint16_t bLen );
#endif
static uint8_t *gnss_data_format_verify( uint8_t *pSrc, uint16_t wLen, const char* pChk, uint16_t* pLen );

static uint32_t gnss_data_valid_verify( void );
static uint32_t gnss_static_filter_process( void );

static uint32_t gnss_data_task_par_init( void );
static void gnss_invalid_time_reg_init(void);
static uint32_t gnss_invalid_time_reg_count(void);
static void gnss_antenna_status_query(void);
static void gnss_module_power_gpio_init( void );
static uint32_t gnss_module_power_control( uint8_t mode );

static void gnss_hal_uart_init( uint32_t bps );
static void  gnss_hal_uart_recv_cb(hal_uart_port_t uart_port, UINT8 *data, UINT16 len, void *arg);
static void gnss_data_update_buf(uint8_t *buf, uint16_t len);
static void gnss_debug_print_fun( uint8_t * data , uint16_t len );

static void gnss_invalid_data_reg_init(void);
static uint8_t gnss_invalid_data_count(void);

static void gnss_invalid_location_reg_init(void);
static uint8_t gnss_invalid_location_count(void);

static uint32_t gnss_task_into_run_mode(void);
static uint32_t gnss_task_into_sleep_mode(void);
static uint32_t gnss_task_into_stop_mode(void);

static void gnss_recv_data_queue_create(void);
static uint32_t gnss_recv_data_queue_get(gnss_recv_buf_typedef *gnss_msg , uint32_t time_out );
static void gnss_data_driver_close( void );

static double radian(double d);
static uint32_t gnss_mileage_calculate( uint32_t lat1, uint32_t lng1, uint32_t lat2, uint32_t lng2 );
static void gnss_mileage_data_update( void );
static void gnss_save_info_flash_write( gnss_save_info_t gnss_infor );
#if( GNSS_QXWZ == 1 )
static uint32_t gnss_basic_data_filtering( gnss_recv_buf_typedef * msg );
#endif
static void gnss_lbs_wifiscan_data_cb( uint8_t type, uint32_t latitude, uint32_t longitude );
/** ****************************************************************************
* @remarks       static void  gnss_hal_uart_recv(hal_uart_port_t uart_port, UINT8 *data, UINT16 len, void *arg)
* @brief         GNSS UART数据接收回调函数
* @param[in]     无
* @param[out]    uart_port 串口号
* @param[out]    *data 接收数据地址
* @param[out]    len 接收数据长度
* @param[out]    *arg 功能参数
* @return        无
* @attention     无
*******************************************************************************/
static void  gnss_hal_uart_recv_cb(hal_uart_port_t uart_port, UINT8 *data, UINT16 len, void *arg)
{
#if( GNSS_GEMU == 1 )
    /*GNSS*/
    gnss_data_update_buf( data , len);
#endif
#if( GNSS_QXWZ == 1 )
    /* qxwz */
    task_modules_e gnss_run_st;
    
    gnss_run_st = power_man_task_state_get( gnss_power_man_id );
    if( gnss_run_st == TASK_RUN_MODE )
    {   
        if( gnss_qxsdk_enable_st == GNSS_QXSDK_ENABLE )  
        {
            qxwz_inject_gnss_data( sdk_hl, data, len );
        }
        else// if( gnss_qxsdk_enable_st == GNSS_QXSDK_DISENABLE )
        {
            gnss_data_update_buf( data , len);
        }
    }
#endif
}

/** ****************************************************************************
* @remarks       void gnss_data_update_buf(uint8_t *buf, uint16_t len)
* @brief         GNSS UART数据更新数据包
* @param[in]     *buf数据地址；
* @param[in]     len数据长度；
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void gnss_data_update_buf(uint8_t *buf, uint16_t len)
{
    gnss_recv_buf_typedef recv_buf;
    gaoz_mutex_lock( gnss_rev_data_mutex );
    if( len > UART_RX_BUF_SIZE ) /*内存边界判断*/
    {
        len = UART_RX_BUF_SIZE; 
    }
    
    recv_buf.data = ( uint8_t *)gaoz_malloc_mem( len + 8 ); /*动态申请空间，空间位置处于FreeRtos总栈空间中*/
    if( recv_buf.data != NULL )
    {   
        memcpy( ( uint8_t *)recv_buf.data , ( uint8_t *)buf ,len  );
        recv_buf.len = len;
        if( gaoz_queue_put( gnss_recv_data_queue, ( void * )&recv_buf , 10 ) < 0 )
        {
            gaoz_free_mem( (void *)recv_buf.data );
        }
    }
    gaoz_mutex_unlock( gnss_rev_data_mutex );
}

/** ****************************************************************************
* @remarks       void gnss_qxwz_data_update_buf(uint8_t *buf, uint16_t len)
* @brief         GNSS UART数据更新数据包
* @param[in]     *buf数据地址；
* @param[in]     len数据长度；
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
void gnss_qxwz_data_update_buf(uint8_t *buf, uint16_t len)
{
    gnss_data_update_buf( buf, len );
}

/** ****************************************************************************
* @remarks       void gnss_data_create_task( unsigned portBASE_TYPE uxPriority )
* @brief         创建GNSS基层数据管理任务
* @param[in]     uxPriority任务优先级；
* @param[out]    无
* @return        无
* @attention     在系统启动后进行创建
*******************************************************************************/
void gnss_data_create_task( unsigned portBASE_TYPE uxPriority )
{   
    gnss_set_time_zone = 0;
    gnss_power_man_id = 0;
    gnss_data_save_location = 0;
    gnss_driving_mileage = 0;
    gnss_driving_latitude = 0;
    gnss_driving_longitude = 0;
    gnss_static_filter_count = 0;
    gnss_static_filter_enable_st = GNSS_SF_ENABLE;
    gnss_qxsdk_enable_st = GNSS_QXSDK_DISENABLE;
	gnss_lbs_position_type = 0;
    gnss_lbs_position_once_state = 0;
    gnss_info_flash_read( &gnss_info_old );     /*FLASH中读取数据*/
    memcpy(( uint8_t * )&gnss_info_now, ( uint8_t * )&gnss_info_old, sizeof( gnss_info_struct ) );
    gnss_data_task_par_init();
    gnss_module_power_gpio_init();
    /*创建GNSS数串口数据接收空间*/
    gnss_recv_data.data  = (uint8_t *)gaoz_fibo_malloc( UART_RX_BUF_SIZE + 10 );
    if( gnss_recv_data.data == NULL )
    {
        while(1); /*创建失败*/
    }
    memset((uint8_t *)gnss_recv_data.data, 0x00 , UART_RX_BUF_SIZE + 10);
    gnss_recv_data.len = 0;
    /*创建GNSS解析的数据 空间地址*/
    gnss_nmea_data.data  = (uint8_t *)gaoz_fibo_malloc( GNSS_NMEA_DATA_LEN );
    memset((uint8_t *)gnss_nmea_data.data, 0x00 , GNSS_NMEA_DATA_LEN);
    gnss_nmea_data.len = 0;
    if( gnss_nmea_data.data == NULL )
    {
        while(1); /*创建失败*/
    }
    /*创建任务互斥体*/
    gnss_info_mutex = gaoz_mutex_create();
    if( gnss_info_mutex == 0 )
    {
        while(1); /*创建失败*/
    }
    gnss_rev_data_mutex  = gaoz_mutex_create();
    if( gnss_rev_data_mutex == 0 )
    {
        while(1); /*创建失败*/
    }
#if( OS_GNSS_MODULE_TYPE == 0 ) 
    gnss_hal_uart_init( 115200 );
#endif
    gnss_info_now.gnss_model_status = GPS_MODEL_OK;     /*系统默认GPS模块正常*/
    gnss_recv_data_queue_create();
    gaoz_thread_create(gnss_data_handle_task, GPS_MAN_NAME, 1024*8, NULL, uxPriority);
#if( GNSS_GEMU == 1 )
	agnss_data_create_task( OSI_PRIORITY_NORMAL );      /*创建AGNSS快速定位服务任务*/
#endif
}

/** ****************************************************************************
* @remarks       static void gnss_recv_data_queue_create(void)
* @brief         创建发送数据消息队列
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void gnss_recv_data_queue_create(void)
{
    /* 创建模块网络发送数据的消息队列 */
    gnss_recv_data_queue = gaoz_queue_create( GNSS_RECV_DATA_QUEUE_DEPTH, sizeof( gnss_recv_buf_typedef ) );
    if( gnss_recv_data_queue == 0 )
    {
        while( 1 ); /*创建失败,进行处理*/
    }
}

/** ****************************************************************************
* @remarks       uint32_t gnss_recv_data_queue_get(gnss_recv_buf_typedef *gnss_msg , uint32_t time_out )
* @brief         获取GNSS数据发送消息队列数据
* @param[in]     *gprs_msg 获取的数据地址
* @param[out]    无
* @return        pdPASS 接收到数据 pdFAIL 未接收到数据
* @attention     必须在任务中运行
*******************************************************************************/
static uint32_t gnss_recv_data_queue_get(gnss_recv_buf_typedef *gnss_msg , uint32_t time_out )
{
    if( gnss_recv_data_queue == 0 )
    {
        gnss_recv_data_queue_create();
    }
    if( gaoz_queue_get( gnss_recv_data_queue, gnss_msg, time_out )  == 0 ) //等待回应信号量
    {
        return pdPASS;
    }
    else
    {
        return pdFAIL;
    }
    return pdFAIL;
}

/** ****************************************************************************
* @remarks       static void gnss_module_power_gpio_init( void )
* @brief         GNSS模块电源使能引脚初始化
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void gnss_module_power_gpio_init( void )
{
    gaoz_gpio_pull_disable(GNSS_POWER_PIN);
    gaoz_gpio_mode_set(GNSS_POWER_PIN,2);
    gaoz_gpio_cfg(GNSS_POWER_PIN,1); /*配置为输出方式*/
    gaoz_gpio_set(GNSS_POWER_PIN,0); /*输出低电平，关闭GNSS电源*/
}
/** ****************************************************************************
* @remarks       static uint32_t gnss_module_power_control( uint8_t mode )
* @brief         控制GNSS模块电源 打开或者关闭
* @param[in]     mode 打开方式 OPEN_GNSS_POWER 打开  CLOSE_GNSS_POWER 关闭
* @param[out]    无
* @return        pdFAIL 失败 pdPASS 成功
* @attention     无
*******************************************************************************/
static uint32_t gnss_module_power_control( uint8_t mode )
{
    uint32_t ret = pdFAIL;
    gnss_info_mutex_take();
    if( mode == GPS_MODEL_OPEN ) /*打开GNSS电源*/
    {
        if( gaoz_gpio_set(GNSS_POWER_PIN,1) == 1 ) /*输出高电平*/
        {
            ret =  pdPASS;
            //gnss_info_now.gnss_model_status = GPS_MODEL_OPEN;
        }
    }
    else if( mode == GPS_MODEL_CLOSE )
    {   
        if( gaoz_gpio_set(GNSS_POWER_PIN,0) == 1 ) /*输出电平*/
        {
            ret =  pdPASS;
            //gnss_info_now.gnss_model_status = GPS_MODEL_CLOSE;
        }
    }
    gnss_info_mutex_give();
    return ret;
}
/** ****************************************************************************
* @remarks       static void gnss_hal_uart_init( void )
* @brief         GNSS串口初始
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void gnss_hal_uart_init( uint32_t bps )
{
    hal_uart_config_t drvcfg = {0};  
#if( GNSS_GEMU == 1 )
    #if( OS_GNSS_MODULE_TYPE == 1 ) /*选择GNSS型号为中科微，通信波特率为115200*/
    drvcfg.baud = bps;
    #else
    drvcfg.baud = bps;              /*选择GNSS型号为泰斗，通信波特率为9600*/
    #endif
#endif
#if( GNSS_QXWZ == 1 )
    drvcfg.baud = 115200;
#endif
    drvcfg.parity = HAL_UART_NO_PARITY;    
    drvcfg.data_bits = HAL_UART_DATA_BITS_8;    
    drvcfg.stop_bits = HAL_UART_STOP_BITS_1;    
    drvcfg.rx_buf_size = UART_RX_BUF_SIZE;    
    drvcfg.tx_buf_size = UART_TX_BUF_SIZE;
#if( GNSS_GEMU == 1 )
    drvcfg.recv_timeout = 100; /*接收时间等待*/
#endif
#if( GNSS_QXWZ == 1 )
    drvcfg.recv_timeout = 20; /*接收时间等待*/
#endif  
    gaoz_hal_uart_init(GNSS_UART_PORT, &drvcfg, gnss_hal_uart_recv_cb, NULL);
}

/** ****************************************************************************
* @remarks       static uint32_t gnss_data_clac_gsv(gnss_info_struct * pGps, gnss_gsv_info_t* gps_gsv_infor_p, gnss_gsv_info_t* bd_gsv_infor_p)
* @brief         计算GSV数据
* @param[in][out]pGps gsv上报数据
* @param[in]     *gps_gsv_infor_p GPS的gsv数据
* @param[in]     *bd_gsv_infor_p BD的gsv数据
* @return        pdTRUE    计算完成 , pdFALSE 空数据
*******************************************************************************/
static uint32_t gnss_data_clac_gsv(gnss_info_struct * pGps, gnss_gsv_info_t* gps_gsv_infor_p, gnss_gsv_info_t* bd_gsv_infor_p)
{
    int i = 0; int j = 0;

    if (pGps == NULL || gps_gsv_infor_p == NULL || bd_gsv_infor_p == NULL) {
        return pdFALSE; 
    }

    for (i = 0; i < gps_gsv_infor_p->total_num_sat; i++)
    {
        if(gps_gsv_infor_p->sat_info[i].sat_cn0 != 0)
        {
            gps_gsv_infor_p->sat_user_info.total_snr += gps_gsv_infor_p->sat_info[i].sat_cn0;
            gps_gsv_infor_p->sat_user_info.valid_total_num_sat++;
        }
    }
    for (j = 0; j < bd_gsv_infor_p->total_num_sat; j++)
    {
        if(bd_gsv_infor_p->sat_info[j].sat_cn0 != 0)
        {
            bd_gsv_infor_p->sat_user_info.total_snr += bd_gsv_infor_p->sat_info[j].sat_cn0;
            bd_gsv_infor_p->sat_user_info.valid_total_num_sat++;
        }
    }

    gps_gsv_infor_p->sat_user_info.snr_avr = (uint8_t)(gps_gsv_infor_p->sat_user_info.total_snr / gps_gsv_infor_p->sat_user_info.valid_total_num_sat);
    bd_gsv_infor_p->sat_user_info.snr_avr = (uint8_t)(bd_gsv_infor_p->sat_user_info.total_snr / bd_gsv_infor_p->sat_user_info.valid_total_num_sat);

    if (gps_gsv_infor_p->sat_user_info.snr_avr != 0 && bd_gsv_infor_p->sat_user_info.snr_avr != 0) {
        pGps->gnss_position_info.snr = (gps_gsv_infor_p->sat_user_info.snr_avr + bd_gsv_infor_p->sat_user_info.snr_avr) / 2;
    } else if (gps_gsv_infor_p->sat_user_info.snr_avr != 0) {
        pGps->gnss_position_info.snr = gps_gsv_infor_p->sat_user_info.snr_avr;
    } else if (bd_gsv_infor_p->sat_user_info.snr_avr != 0) {
        pGps->gnss_position_info.snr = bd_gsv_infor_p->sat_user_info.snr_avr;
    } else {    // 两个都为0
        pGps->gnss_position_info.snr = 0;
    }
    
    pGps->gnss_position_info.gps_total_num_sat = gps_gsv_infor_p->total_num_sat;
    pGps->gnss_position_info.valid_gps_total_num_sat = gps_gsv_infor_p->sat_user_info.valid_total_num_sat;
    pGps->gnss_position_info.bd_total_num_sat = bd_gsv_infor_p->total_num_sat;
    pGps->gnss_position_info.valid_bd_total_num_sat = bd_gsv_infor_p->sat_user_info.valid_total_num_sat;

    // log_debug_printf(INFOR_MODE , GPS_MAN_NAME ,"snr:%d, gps_total_num_sat:%d, valid_gps_total_num_sat:%d, bd_total_num_sat:%d, valid_bd_total_num_sat:%d",
    // pGps->gnss_position_info.snr, pGps->gnss_position_info.gps_total_num_sat, pGps->gnss_position_info.valid_gps_total_num_sat, 
    // pGps->gnss_position_info.bd_total_num_sat, pGps->gnss_position_info.valid_bd_total_num_sat);
    // log_debug_printf(INFOR_MODE , GPS_MAN_NAME ,"gps_total_num_sat:%d" , pGps->gnss_position_info.gps_total_num_sat);
    // log_debug_printf(INFOR_MODE , GPS_MAN_NAME ,"valid_gps_total_num_sat:%d" , pGps->gnss_position_info.valid_gps_total_num_sat);
    // log_debug_printf(INFOR_MODE , GPS_MAN_NAME ,"bd_total_num_sat:%d" , pGps->gnss_position_info.bd_total_num_sat);
    // log_debug_printf(INFOR_MODE , GPS_MAN_NAME ,"valid_bd_total_num_sat:%d" , pGps->gnss_position_info.valid_bd_total_num_sat);

    return pdTRUE;
}
 

 
/** ****************************************************************************
* @remarks       static uint32_t gnss_get_sats_info( gnss_gsv_info_t* gnss_gsv_infor, uint8_t *pSrc, uint16_t bLen )
* @brief         获取GSV数据包
* @param[in][out]*gnss_gsv_infor gsv数据
* @param[in]     *pSrc 数据源地址
* @param[in]     bLen 数据长度
* @return        pdTRUE    含有有效GSV数据包，将相关数据放入到GPS数结构中 , pdFALSE 没有有效GSV数据包，提取当前可视卫星总数
* @attention     $GPGSV,3,1,10,27,66,039,39,08,66,230,38,04,39,221,34,09,38,270,34,1*68
* @attention     $BDGSV,3,1,10,27,66,039,39,08,66,230,38,04,39,221,34,09,38,270,34,1*68
*******************************************************************************/
static uint32_t gnss_get_sats_info( gnss_gsv_info_t* gnss_gsv_infor, uint8_t *pSrc, uint16_t bLen )
{
    uint8_t *p_str = NULL;
    const char check_str[2] = ",";
    uint8_t for_count = 0;
    int j = 0;
    uint8_t gsv_data[100] = {0};

    if (gnss_gsv_infor == NULL) {
        return pdFALSE;
    }

    // +7跳过"$GPGSV,"
    // 把有连在一起的','中间插入'0',这样可以用strtok处理，例如"1,1,2,,,3,4"转换成"1,1,2,0,0,3,4"
    for (int i = 7; i < bLen; i++) {
        gsv_data[j++] = pSrc[i];
        if (pSrc[i] == ',' && pSrc[i+1] == ',') {
            gsv_data[j++] = '0';
        }
    }
    gsv_data[j++] = '\0';
    // log_debug_printf(INFOR_MODE , GPS_MAN_NAME ,"gsv_data:%s" , gsv_data);

    p_str = strtok(gsv_data, check_str);
    if (p_str == NULL) { return pdFALSE; }
    // 获取语句总数
    gnss_gsv_infor->total_num_sen = (uint8_t)strtol(p_str, NULL, 10);
    // log_debug_printf(INFOR_MODE , GPS_MAN_NAME ,"total_num_sen_d:%d" , gnss_gsv_infor->total_num_sen);
    p_str = strtok(NULL, check_str);
    if (p_str == NULL) { return pdFALSE; }
    // 获取语句号
    gnss_gsv_infor->sen_num = (uint8_t)strtol(p_str, NULL, 10);
    // log_debug_printf(INFOR_MODE , GPS_MAN_NAME ,"sen_num_d:%d" , gnss_gsv_infor->sen_num);
    p_str = strtok(NULL, check_str);
    if (p_str == NULL) { return pdFALSE; }
    // 获取可视的卫星总数
    gnss_gsv_infor->total_num_sat = (uint8_t)strtol(p_str, NULL, 10);
    // log_debug_printf(INFOR_MODE , GPS_MAN_NAME ,"total_num_sat_d:%d" , gnss_gsv_infor->total_num_sat);
    p_str = strtok(NULL, check_str);
    if (p_str == NULL) { return pdFALSE; }

    if (gnss_gsv_infor->total_num_sat == 0) {  // 没有可用星数
        return pdTRUE;
    }

    // 计算循环次数
    for_count = (gnss_gsv_infor->total_num_sen == gnss_gsv_infor->sen_num) ? ((gnss_gsv_infor->total_num_sat % 4) ? gnss_gsv_infor->total_num_sat % 4 : 4) : 4;
    for (int count = 0; (count < for_count) && (p_str != NULL); count++) {
        // 卫星标识号
        // log_debug_printf(INFOR_MODE , GPS_MAN_NAME ,"pGps->gnss_position_info.id:%s" , p_str );
        // gnss_gsv_infor->sat_info[(gnss_gsv_infor->sen_num-1)*4+count].sat_id = (uint8_t)strtol(p_str, NULL, 10);
        p_str = strtok(NULL, check_str);
        // 仰角
        // log_debug_printf(INFOR_MODE , GPS_MAN_NAME ,"pGps->gnss_position_info.angle:%s" , p_str );
        // gnss_gsv_infor->sat_info[(gnss_gsv_infor->sen_num-1)*4+count].sat_elev = (uint8_t)strtol(p_str, NULL, 10);
        p_str = strtok(NULL, check_str);
        // 真方位角
        // log_debug_printf(INFOR_MODE , GPS_MAN_NAME ,"pGps->gnss_position_info.angle2:%s" , p_str );
        // gnss_gsv_infor->sat_info[(gnss_gsv_infor->sen_num-1)*4+count].sat_az = (uint8_t)strtol(p_str, NULL, 10);
        p_str = strtok(NULL, check_str);
        // 载噪比
        // log_debug_printf(INFOR_MODE , GPS_MAN_NAME ,"pGps->gnss_position_info.snr:%s" , p_str );
        gnss_gsv_infor->sat_info[(gnss_gsv_infor->sen_num-1)*4+count].sat_cn0 = (uint8_t)strtol(p_str, NULL, 10);
        p_str = strtok(NULL, check_str);
    }

    return pdTRUE;
}

/** ****************************************************************************
* @remarks       static uint32_t gnss_data_parse_gsv( gnss_gsv_info_t* gps_gsv_infor_p, gnss_gsv_info_t* bd_gsv_infor_p, uint8_t *pSrc, uint16_t bLen )
* @brief         检查是不是含有GPS和BD的GSV数据包
* @param[in][out]    * gps_gsv_infor_p 存储的GSV数据
* @param[in][out]    * bd_gsv_infor_p 存储的BD数据
* @param[in]     *pSrc 数据源地址
* @param[in]     bLen 数据长度
* @return        pdTRUE    含有GPS和BD的GSV数据
* @attention     $GPGSV,3,1,10,27,66,039,39,08,66,230,38,04,39,221,34,09,38,270,34,1*68
* @attention     $BDGSV,3,1,10,27,66,039,39,08,66,230,38,04,39,221,34,09,38,270,34,1*68
*******************************************************************************/
static uint32_t gnss_data_parse_gsv( gnss_gsv_info_t* gps_gsv_infor_p, gnss_gsv_info_t* bd_gsv_infor_p, uint8_t *pSrc, uint16_t bLen )
{
    if (gps_gsv_infor_p == NULL || bd_gsv_infor_p ==NULL || pSrc == NULL || bLen == 0) {
        return pdFALSE;
    }

    if (!memcmp(pSrc, "$GP", 3)) {
        gnss_get_sats_info(gps_gsv_infor_p, pSrc, bLen);
    } else if (!memcmp(pSrc, "$BD", 3)) {
        gnss_get_sats_info(bd_gsv_infor_p, pSrc, bLen);
    } else {
        return pdFALSE;
    }

    return pdTRUE;
}

/** ****************************************************************************
* @remarks       static uint32_t gnss_data_info_parse( uint8_t *pSrc, uint16_t wLen )
* @brief         GNSS数据处理
* @param[in]     *pSrc 数据源地址
* @param[in]     wLen 数据长度
* @param[out]    无
* @return        GNSS_DATA_OK 解析数据成功 GNSS_DATA_ERR 解析数据失败
* @attention     无
*******************************************************************************/
static uint32_t gnss_data_info_parse( uint8_t *pSrc, uint16_t wLen )
{
    #define GPS_COVERAGE_TIME   ( 3600 )
    uint8_t *p = NULL;
    uint8_t *p_gsv = NULL;
    uint8_t *p_gsv_2 = NULL;
    uint16_t len = 0;
    uint32_t ret = GNSS_DATA_ERR;
    static uint8_t rmcf = GNSS_GMC_ERR, ggaf = GNSS_GGA_ERR, gsaf = GNSS_GSA_ERR;

    gnss_info_mutex_take();
    if(( p = gnss_data_format_verify( pSrc, wLen, "RMC", &len ) ) != NULL )
    {
        /* RMC数据：时间、经度、纬度、速度、方位、经纬度指示 */
        gnss_debug_print_fun(( uint8_t * )p,len );
        gnss_data_parse_rmc( &gnss_info_now, p, len );
        rmcf = GNSS_GMC_OK;
    }
    /* 检查数据是否有GGA数据 */
    if(( p = gnss_data_format_verify( pSrc, wLen, "GGA", &len ) ) != NULL )
    {
        /* GGA数据：判断是否定位、当前可用卫星数、高程信息 */
        gnss_debug_print_fun(( uint8_t * )p,len );
        gnss_data_parse_gga( &gnss_info_now, p, len );
        ggaf = GNSS_GGA_OK;
    }
    /* 检查数据是否有GSA数据 */
    if(( p = gnss_data_format_verify( pSrc, wLen, "GSA", &len ) ) != NULL )
    {
        gnss_debug_print_fun(( uint8_t * )p,len );
        gnss_data_parse_gsa( &gnss_info_now, p, len );
        gsaf = GNSS_GSA_OK;
    }
#if( OS_GNSS_MODULE_TYPE == 1 ) /*选择GNSS型号为中科微，通信波特率为115200*/
    /* 检查数据是否有TXT数据 */
    if(( p = gnss_data_format_verify( pSrc, wLen, "TXT", &len ) ) != NULL )
    {
        gnss_debug_print_fun(( uint8_t * )p,len );
        gnss_data_parse_txt( &gnss_info_now, p, len );
        gsaf = GNSS_GSA_OK;
    }
#endif
    /* GSV数据的获取 */
    gnss_gsv_info_t gps_gsv_infor_t = {0};
    gnss_gsv_info_t bd_gsv_infor_t = {0};
    // 偏移到第一个出现“$**GSV”的地方
    p_gsv = ( uint8_t* )strstr(( const char* )pSrc, "GSV" );
    if( p_gsv != NULL ) 
    {
        wLen -= ((p_gsv - 3) - pSrc);
        pSrc = p_gsv - 3;   // 3是$**的长度 
    }
    // log_debug_printf(INFOR_MODE , "GPGSV" ,"wLen:%d, pSrc:%d, p_gsv:%d" , wLen, pSrc, p_gsv);
    // 一直检查数据是否有GSV数据
    while(( (p = gnss_data_format_verify( (uint8_t *)pSrc, wLen, "GSV", &len ) ) != NULL)  && 
            (wLen > 0) && 
            ((p_gsv_2 = ( uint8_t* )strnstr(( const char* )pSrc, "GSV", wLen)) != NULL))
    {
        // log_debug_printf(INFOR_MODE , "GPGSV" ,"len:%d, pSrc:%d, p:%d, wLen:%d" , len, pSrc, p, wLen);
        // gnss_debug_print_fun(( uint8_t * )p,len );
        gnss_data_parse_gsv( &gps_gsv_infor_t, &bd_gsv_infor_t, p, len );
        gsaf = GNSS_GSV_OK;

        pSrc += len;
        if ((int16_t)wLen - (int16_t)len <= 0) {
            wLen = 0;
        } else {
            wLen -= len;
        }
    }
    gnss_data_clac_gsv(&gnss_info_now, &gps_gsv_infor_t, &bd_gsv_infor_t);  // 计算SNR和一些可视参数

#if( GNSS_QXWZ == 1 )
    /* 检查定位校验数据是否存在 GPDRC4，如果存在需要对数据进行保存*/
    if(( p = gnss_data_format_verify( pSrc, wLen, "DRC4", &len ) ) != NULL )
    {
        gnss_debug_print_fun(( uint8_t * )p,len );
        memset((uint8_t *)gnss_gpdrc4_data_buf, 0x00, GNSS_GPDRC4_DATA_LEN );
        if( len < GNSS_GPDRC4_DATA_LEN )
        {
            memcpy((uint8_t *)gnss_gpdrc4_data_buf, (uint8_t *)p, len );
        }
    }
    /* 检查服务器参数校验数据是否存在 $GPDRC，如果存在需要对数据进行保存*/
    else if(( p = gnss_data_format_verify( pSrc, wLen, "DRC", &len ) ) != NULL )
    {
        gnss_debug_print_fun(( uint8_t * )p,len );
        memset((uint8_t *)gnss_gpdrc_data_buf, 0x00, GNSS_GPDRC_DATA_LEN );
        if( len < GNSS_GPDRC_DATA_LEN )
        {
            memcpy((uint8_t *)gnss_gpdrc_data_buf, (uint8_t *)p, len );
        }
    }
#endif
     /* GSV数据直接复制，上传数据都是gnss_info_old数据 */
    gnss_info_old.gnss_position_info.sat_num = gnss_info_now.gnss_position_info.sat_num;
    gnss_info_old.gnss_position_info.snr = gnss_info_now.gnss_position_info.snr;
    gnss_info_old.gnss_position_info.valid_gps_total_num_sat = gnss_info_now.gnss_position_info.valid_gps_total_num_sat;
    gnss_info_old.gnss_position_info.valid_bd_total_num_sat = gnss_info_now.gnss_position_info.valid_bd_total_num_sat;

    /*产生有效的定位数据，将数据有效标识清空，等待新的数据进行填充*/ 
    if(( rmcf == GNSS_GMC_OK ) || ( ggaf == GNSS_GGA_OK ) || ( gsaf == GNSS_GSA_OK ))
    {
        rmcf = GNSS_GMC_ERR; ggaf = GNSS_GGA_ERR; gsaf = GNSS_GSA_ERR;
        ret = GNSS_DATA_OK;
        if( gnss_info_now.gnss_position_info.pos_flag == 1 )
        {
            gnss_lbs_position_type = 0;
            gnss_info_now.gnss_position_info.is_valid = 1;
            gnss_info_old.gnss_position_info.pos_flag = 1;
            if( gnss_data_valid_verify() == pdPASS )
            {
                memcpy(( uint8_t * )&gnss_info_old, ( uint8_t * )&gnss_info_now, sizeof( gnss_info_struct ) );
            }
            else
            {
                if(( gnss_info_old.gnss_position_info.latitude == 0 )  || ( gnss_info_old.gnss_position_info.longitude == 0 ) || (gnss_reset == 0))
                {
                    gnss_reset = 1;
                    gnss_info_now.gnss_position_info.pos_static = 1;
                    memcpy(( uint8_t * )&gnss_info_old, ( uint8_t * )&gnss_info_now, sizeof( gnss_info_struct ) );
                }
            }
        }
        else
        {   /*没有产生有效的定位数据*/
            gnss_info_now.gnss_position_info.is_valid = 0;
            gnss_info_now.gnss_position_info.pos_static = 0;
            /*将历史数据寄存器敏感数据清空，保留最后的定位经纬度数据*/
            gnss_info_old.gnss_position_info.is_valid = 0;
            gnss_info_old.gnss_position_info.pos_flag = 0;    /*设置历史数据定位无效*/
            gnss_info_old.gnss_position_info.speed = 0;       /*设置当前速度为0*/
            gnss_valid_speed_count = 0;
            gnss_static_filter_buf.cnt = 0;
        }
    }
    gnss_info_mutex_give();
    return( ret );
}

/** ****************************************************************************
* @remarks       static uint32_t gnss_data_parse_rmc( gnss_info_struct * pGps, uint8_t *pSrc, uint16_t bLen )
* @brief         GNSS数据处理，解析RMC格式数据
* @param[in]     *pSrc 数据源地址
* @param[in]     bLen 数据长度
* @param[out]    *pGps 解析数据地址
* @return        pdTRUE 含有有效RMC数据包，将数据放入到GPS数结构中 ， pdFALSE 没有有效RMC数据包
* @attention     点位保存格式为mmmm_mmmm,精确到万分之一分。
*                ddmm.mmmm = 3950.00403 ~= 3950.0040
*                3950.00403 = (39 * 60 + 50) * 10000 + 0.00403 * 10000 = 23900000 + 40 = 23900040
*                点位还原算法：
*                mmmm_mmmm = 23900040
*                _mmmm = mmmm_mmmm % 10000 = 40
*                mmmm = (mmmm_mmmm - _mmmm ) / 10000 = 2390
*                dd = mmmm / 60 = 39
*                mm = mmmm % 60 = 50
*                ddmm.mmmm = 3950.0040

*******************************************************************************/
static uint32_t gnss_data_parse_rmc( gnss_info_struct *pGps, uint8_t *pSrc, uint16_t bLen )
{
    uint16_t i, j;
    uint8_t *p1, *p2;
    uint8_t data[16];
    uint32_t temp; 
    float ft;
    /* 跳过数据头"$GPRMC"，指向第一个',' */
    p1 = pSrc + 6;
    /* 检查定位状态,如果不定位，则只读取当前卫星颗数 */
    p2 = ( uint8_t* )strnchar(( const char* )p1, ',', RMC_PFS_POS );

    if( p2 == NULL )
    {
        return pdFALSE;
    }
    if( p2[1] == 'A' )
    {
        pGps->gnss_position_info.pos_flag = 1;
    }
    else
    {
        pGps->gnss_position_info.pos_flag = 0;
    }
    /* 已定位，解析数据 */
    i = 1;

    while( *p1++ != '*' )
    {
        if( *p1 == ',' )
        {
            i++;
            continue;
        }

        j = 0;

        while( *p1 != ',' && *p1 != '*' )
        {
            data[j++] = *p1++;
        }

        data[j] = '\0';

        switch( i )
        {
            case RMC_UTC_POS:
                pGps->gnss_position_info.time.hour = (( data[0] & 0xF ) << 4 ) + ( data[1] & 0xF );
                pGps->gnss_position_info.time.minute = (( data[2] & 0xF ) << 4 ) + ( data[3] & 0xF );
                pGps->gnss_position_info.time.second = (( data[4] & 0xF ) << 4 ) + ( data[5] & 0xF );
                break;

            case RMC_PFS_POS:
                break;
            
            case RMC_LAT_POS:   // 维度计算 ddmm.mmmm
                ft=atof((const char *)(data));
                pGps->gnss_position_info.latitude = (uint32_t)(ft/100);
                pGps->gnss_position_info.latitude *= 1000000;            // 度*1000000
                temp = (uint32_t)(ft*10000);                             // 度*1000000+分*10000  
                temp = temp%1000000*100/60;                              // 分*10000 *100 /60,单位【度*1000000】
                pGps->gnss_position_info.latitude += temp;
                break;
            case RMC_NSI_POS:
                pGps->gnss_position_info.nsi = data[0];
                break;
                
            case RMC_LON_POS:   //经度计算
                ft = atof((const char *)(data));
                pGps->gnss_position_info.longitude = (uint32_t)(ft/100);
                pGps->gnss_position_info.longitude *= 1000000;          // 度*1000000
                temp = (uint32_t)(ft*10000);                            // 度*1000000+分*10000  
                temp = temp%1000000*100/60;                             // 分*10000 *100 /60,单位【度*1000000】
                pGps->gnss_position_info.longitude += temp;
                break;

            case RMC_EWI_POS:
                pGps->gnss_position_info.ewi = data[0];
                break;
                
            case RMC_SPD_POS:
                /************************************************************************
                速度: xxx.x 节(1节 = 1.85185185km/h),速度计算成km/h,(speed * 185)/100,
                185和100有公约数5,则算式可以改为(speed * 37) / 20,避免计算溢出。
                ************************************************************************/
                temp = str_to_int_precision( data, j, 1 );
                pGps->gnss_position_info.speed = ( temp * 37 ) / 20;
                break;

            case RMC_ORI_POS:
                pGps->gnss_position_info.direction = str_to_int_precision( data, j, 1 )/10;
                break;

            case RMC_DAT_POS:
                pGps->gnss_position_info.time.day = (( data[0] & 0xF ) << 4 ) + ( data[1] & 0xF );
                pGps->gnss_position_info.time.month = (( data[2] & 0xF ) << 4 ) + ( data[3] & 0xF );
                pGps->gnss_position_info.time.year = (( data[4] & 0xF ) << 4 ) + ( data[5] & 0xF );
                break;
            default :
                break;
        }

        if( *p1 == '*' ) break;
        i++;
        j = 0;
    }

    return pdTRUE;
}

/** ****************************************************************************
* @remarks       static uint8_t *gnss_data_format_verify( uint8_t *pSrc, uint16_t wLen, const char* pChk, uint16_t* pLen )
* @brief         检验GPS接收数据中是否含有有效的数据包
* @param[in]     *pSrc 数据源地址
* @param[in]     wLen 数据长度
* @param[out]    * pChk 需要检验的数据标识 RMC、GGA等
* @param[out]    *pLen 有效的数据长度
* @return        GNSS_DATA_OK 解析数据成功 GNSS_DATA_ERR 解析数据失败
* @attention     pstart  有效数据的头指针，指向'$'字符
*                pLen    有效数据的长度，通过指针传递给调用者，长度范围从'$'字符到
*                最后的校验位。
*******************************************************************************/
static uint8_t *gnss_data_format_verify( uint8_t *pSrc, uint16_t wLen, const char* pChk, uint16_t*pLen )
{
    uint8_t ch_sum;
    uint8_t *p, *pstart;
    uint16_t len;
    
    *pLen = 0;
    p = ( uint8_t* )strstr(( const char* )pSrc, ( const char* )pChk );
    if( p == NULL ) 
    {
        return ( NULL );
    }
    /* point to the first valid character, skip the '$'. */
    pstart = p - 2;
    //pstart = p;
    /* skip data flag (eg. "GGA," or "RMC,") for fast search. */
    p += 4;
    len = wLen - ( p - pSrc ) - 1;
    p = memchr( p, '*', len );
    
    if( p == NULL )
    {
        return ( NULL );
    }
    
    if( p[1] > 0x39 )
    {
        ch_sum = ( p[1] - 0x37 ) << 4;
    }
    else
    {
        ch_sum = ( p[1] - 0x30 ) << 4;
    }
    
    if( p[2] > 0x39 )
    {
        ch_sum += ( p[2] - 0x37 );
    }
    else
    {
        ch_sum += ( p[2] - 0x30 );
    }
    
    len = p - pstart;
    
    if( ch_sum != check_calc_xor(( const char* )pstart, len ) )
    {
        return( NULL );
    }
    /* Add '$'/'*'/checksum while calculating the valid data length. */
    *pLen =    len + 4;
    /* point to the '$'. */
    return( --pstart );
}

/** ****************************************************************************
* @remarks       static uint32_t gnss_data_parse_gga( gnss_info_struct * pGps, uint8_t *pSrc, uint16_t bLen )
* @brief         解析GGA数据包
* @param[in]     *pSrc 数据源地址
* @param[in]     bLen 数据长度
* @param[out]    * pGps 目标数据指针
* @return        TURE    含有有效GGA数据包，将数据放入到GPS数结构中 , FALSE 没有有效GGA数据包，提取当前可用卫星数
* @attention     $GPGGA,140657.00,3950.01222,N,11616.75409,E,1,04,8.38,6.2,M,-8.8,M,,*41
*                $GPGGA,140700.00,3950.01915,N,11616.75650,E,1,04,8.36,3.9,M,-8.8,M,,*43
                 $GNGGA,094135.00,4004.25270,N,11617.79846,E,1,05,1.83,37.0,M,-8.9,M,,*69
*******************************************************************************/
static uint32_t gnss_data_parse_gga( gnss_info_struct * pGps, uint8_t *pSrc, uint16_t bLen )
{
    uint16_t i, j;
    uint8_t *p1, *p2;
    uint8_t data[16];
    uint8_t fs = 0;
    uint32_t temp; 
    float ft;
    /* 跳过数据头"$GPGGA"，指向第一个',' */
    p1 = pSrc + 6;
    /* 检查定位状态,如果不定位，则只读取当前卫星颗数 */
    if(( p2 = ( uint8_t* )strnchar(( const char* )p1, ',', GGA_PFS_POS ) ) == NULL )
    {
        return FALSE;
    }
    else
    {
        fs = *(p2+1);
        if( fs > '0' )
        {
            pGps->gnss_position_info.gga_fs = fs - '0'; /*获取当前定位质量*/
        }
    }
    
    p2 += 3;
    i = 0;
    
    while( *p2 != ',' )
    {
        data[i++] = *p2++;
    }
    
    /* 获取卫星数 */
    data[i] = '\0';
    pGps->gnss_position_info.sat_num = atoi( (const char *)data );
    /* 已定位，解析数据 */
    i = 1;
    
    while( *p1++ != '*' )
    {
        if( *p1 == ',' )
        {
            i++;
            continue;
        }
        
        if( i != GGA_ALT_POS )  continue;
        
        j = 0;
        
        while( *p1 != ',' && *p1 != '*' )
        {
            data[j++] = *p1++;
        }

        data[j] = '\0';

        switch( i )
        {
            case GGA_UTC_POS:
                break; 
            case GGA_LAT_POS:  // 维度计算
                ft=atof((const char *)(data));
                pGps->gnss_position_info.latitude = (uint32_t)(ft/100);
                pGps->gnss_position_info.latitude *= 1000000;   // 度*1000000
                temp = (uint32_t)(ft*10000);                     // 度*1000000+分*10000  
                temp = temp%1000000*100/60;                    // 分*10000 *100 /60,单位【度*1000000】
                pGps->gnss_position_info.latitude += temp;
                break;
            case GGA_NSI_POS:
                pGps->gnss_position_info.nsi = data[0];
                break;
            case GGA_LON_POS:  //经度计算
                ft = atof((const char *)(data));
                pGps->gnss_position_info.longitude = (uint32_t)(ft/100);
                pGps->gnss_position_info.longitude *= 1000000;  // 度*1000000
                temp = (uint32_t)(ft*10000);                     // 度*1000000+分*10000  
                temp = temp%1000000*100/60;                  // 分*10000 *100 /60,单位【度*1000000】
                pGps->gnss_position_info.longitude += temp;
                break;
            case GGA_EWI_POS:
                pGps->gnss_position_info.ewi = data[0];
                break;
            case GGA_HDOP_POS:
                break;
            case GGA_ALT_POS:
                pGps->gnss_position_info.altitude = str_to_int_precision( data, j, 1 );
                break;
            case GGA_GEO_POS:
                break;
            case GGA_DIFF_AGE_POS:
                break;
            case GGA_DIFF_ID_POS:
                break;
        }

        if( *p1 == '*' )  break;
        
        i++;
        j = 0;
    }
    return pdTRUE;
}

/** ****************************************************************************
* @remarks       static uint32_t gnss_data_parse_gsa( gnss_info_struct * pGps, uint8_t *pSrc, uint16_t bLen )
* @brief         解析GSA数据包
* @param[in]     *pSrc 数据源地址
* @param[in]     bLen 数据长度
* @param[out]    * pGps 目标数据指针
* @return        TURE    含有有效GGA数据包，将数据放入到GPS数结构中 , FALSE 没有有效GGA数据包，提取当前可用卫星数
* @attention     $GNGSA,A,3,03,16,26,31,32,04,25,29,22,,,,1.40,0.88,1.09*1A
*******************************************************************************/
static uint32_t gnss_data_parse_gsa( gnss_info_struct * pGps, uint8_t *pSrc, uint16_t bLen )
{
    uint8_t *p1 = NULL, *p2 = NULL;
    uint8_t mode = 0;
    uint16_t pdop = 0;
    uint8_t data[16] = { 0 };
    uint8_t i = 0;
    /* 跳过数据头"$GPGSA"，指向第一个',' */
    p1 = pSrc + 6;
    /* 检查模式,1-定位不可用，2=2D，3=3D */
    if(( p2 = ( uint8_t* )strnchar(( const char* )p1, ',', GSA_MODE_POS ) ) == NULL )
    {
        return FALSE;
    }
    else
    {
        mode = *( p2 + 1 );
        if( mode > '0' )
        {
            pGps->gnss_position_info.pos_mode = mode - '0';
        }
    }
    /* 检查位置精度因子,只解析出小数点前一位*/
    if(( p2 = ( uint8_t* )strnchar(( const char* )p1, ',', GSA_PDOP_POS ) ) == NULL )
    {
        return FALSE;
    }
    else
    {
        p2 = ( p2 + 1 );
        while( ( *p2 != ',') && ( *p2 != '*' ) )
        {
            data[i++] = *p2++;
        }
        data[i] = '\0';
        
        pdop = str_to_int_precision( data, i, 1 );
        if( pdop > 0 )
        {   
            pGps->gnss_position_info.pdop = pdop / 10; 
        }
    }
    
    return pdTRUE;
}


/** ****************************************************************************
* @remarks       static uint32_t gnss_data_parse_txt( gnss_info_struct * pGps, uint8_t *pSrc, uint16_t bLen )
* @brief         解析GPTXT数据包
* @param[in]     *pSrc 数据源地址
* @param[in]     bLen 数据长度
* @param[out]    * pGps 目标数据指针
* @return        TURE    含有有效GGA数据包，将数据放入到GPS数结构中 , FALSE 没有有效GGA数据包，提取当前可用卫星数
* @attention     $GPTXT,01,01,02,MS=7,11,110D0D38,33,8,08101480,33,0,00000000*5E
*******************************************************************************/
#if( OS_GNSS_MODULE_TYPE == 1 ) /*选择GNSS型号为中科微，通信波特率为115200*/
static uint32_t gnss_data_parse_txt( gnss_info_struct * pGps, uint8_t *pSrc, uint16_t bLen )
{
    uint8_t *p1 = NULL, *p2 = NULL;
    uint8_t data[16] = { 0 };
    uint8_t i = 0,gps_num = 0,bd_num = 0;
    uint8_t ms_flag = 0;
    /* 跳过数据头"$GPTXT"，指向第一个',' */
    p1 = pSrc + 6;
    /*获取GPS卫星数量*/
    if(( p2 = ( uint8_t* )strnchar(( const char* )p1, ',', 4 ) ) == NULL )
    {
        return FALSE;
    }
    else
    {
        p2 = ( p2 + 1 );
        if( ( p2[0] =='M' ) && ( p2[1] =='S' ) )
        {
            ms_flag = 1;
        }
    }
    /*判断AGPS复制定位信息*/
    if( ms_flag == 1 )
    {
        /*获取GPS卫星数量*/
        if(( p2 = ( uint8_t* )strnchar(( const char* )p1, ',', 5 ) ) == NULL )
        {
            return FALSE;
        }
        else
        {
            i = 0;
            p2 = ( p2 + 1 );
            while( ( *p2 != ',') && ( *p2 != '*' ) )
            {
                data[i++] = *p2++;
            }
            data[i] = '\0';
            gps_num = atoi( (const char *)data );
        }
        /*获取北斗卫星数量*/
        if(( p2 = ( uint8_t* )strnchar(( const char* )p1, ',', 8 ) ) == NULL )
        {
            return FALSE;
        }
        else
        {
            i = 0;
            p2 = ( p2 + 1 );
            while( ( *p2 != ',') && ( *p2 != '*' ) )
            {
                data[i++] = *p2++;
            }
            data[i] = '\0';
            bd_num = atoi( (const char *)data );
        }
        pGps->gnss_position_info.agps_num = gps_num + bd_num;
    }

    return pdTRUE;
}
#endif
/** ****************************************************************************
* @remarks       static uint32_t gnss_data_valid_verify( void )
* @brief         GNSS数据的正确性验证
* @param[in]     无
* @param[out]    无
* @return        pdPASS 数据判断成功    ；pdFAIL数据判断失败
* @attention     无
*******************************************************************************/
static uint32_t gnss_data_valid_verify( void )
{
    uint32_t ret = pdFAIL;
    uint8_t  sat_num = GNSS_VALID_SAT_NUM;
    uint32_t veh_speed = event_input_data_get( EVENT_SPEED );               /*获取当前车辆的速度*/

    if(( gnss_info_now.gnss_position_info.pos_mode == 3 ) || ( gnss_info_now.gnss_position_info.gga_fs != 0))  /*判断定位方式是否为3D模式*/
    {          
        if(( gnss_info_now.gnss_position_info.gga_fs == 0x06 ) || 
            ( gnss_info_now.gnss_position_info.gga_fs == 0x07)  ||
                ( gnss_info_now.gnss_position_info.gga_fs == 0x8 )) 
        {
            sat_num = 0;
        }                 
        
        if( gnss_info_now.gnss_position_info.speed < GNSS_MAX_SPEED )       /*判断GPS速度是小于200km/h，速度正常*/
        {
            if(( gnss_info_now.gnss_position_info.speed >= GNSS_MIN_SPEED ) || ( veh_speed >= GNSS_MIN_SPEED ))  /*判断GPS/车辆速度大于3km/h 范围内*/
            {
                gnss_valid_speed_count ++;                                  /*速度有效计数器加一*/
            }
            else
            {
                gnss_valid_speed_count = 0;
            }
            
            if( gnss_valid_speed_count >= GNSS_VALID_SPEED_COUNT )          /*GPS速度有效计数大于等于3次后，进行GPS数据更新*/
            {
                if( gnss_static_filter_enable_state_get() != GNSS_SF_ENABLE )
                {
                    gnss_static_filter_enable_state_set( GNSS_SF_ENABLE );  /*当检测到速度状态有效时开启GNSS静止数据过滤使能状态*/
                }
                gnss_valid_speed_count = GNSS_VALID_SPEED_COUNT;
                gnss_static_filter_buf.cnt = 0;                             /*清空静态过滤缓存寄存器*/        
                if( gnss_info_now.gnss_position_info.sat_num >= sat_num )
                {   
                    gnss_info_now.gnss_position_info.pos_static = 2;
                    ret = pdPASS;                                           /*GPS数据判断正常*/
                }
                else
                {
                    ret =pdFAIL;
                }
            }
            else
            {
                if(( gnss_info_now.gnss_position_info.sat_num >= sat_num )  && ( gnss_info_now.gnss_position_info.pdop < GNSS_POS_PDOP ))
                {   /*判断当前GNSS 静态数据过滤状态是否被使能，如果处于失能状态时则不进行数据更新*/
                    // if( gnss_static_filter_enable_state_get() == GNSS_SF_ENABLE )
                    // {
                        if( gnss_static_filter_process() == pdPASS )    //静态过滤算法
                        {
                            gnss_static_filter_count ++;
                            ret = pdPASS;
                        }
                        else
                        {
                            ret =pdFAIL;
                        }
                    // }
                    // else
                    // {
                    //     gnss_static_filter_count ++;
                    //     ret =pdFAIL;
                    // }
                }
                else
                {
                    ret =pdFAIL;
                }
            }
        }
        else
        {
            ret =pdFAIL;
        }
    }
    else
    {
        ret =pdFAIL;
    }
    return ret;
}

/** ****************************************************************************
* @remarks       static uint32_t gnss_static_filter_process( void )
* @brief         GNSS静态数据过滤
* @param[in]     无
* @param[out]    无
* @return        pdPASS 数据过滤成功    ；pdFAIL数据过滤失败
* @attention     无
*******************************************************************************/
static uint32_t gnss_static_filter_process( void )
{
	uint32_t ret = pdFAIL;
    uint8_t i = 0 , j = 0 , cnt = 0;
    uint32_t distance = 0, direction = 0;
    uint8_t density_cnt_max = 0, angle_cnt_max  = 0;
    uint64_t lat_sum = 0, lon_sum = 0;
    
	if( gnss_static_filter_buf.cnt < GNSS_STATIC_FILTER_BUF_SUM )
	{
		gnss_static_filter_buf.unit[gnss_static_filter_buf.cnt].lat = gnss_info_now.gnss_position_info.latitude;
		gnss_static_filter_buf.unit[gnss_static_filter_buf.cnt].lon = gnss_info_now.gnss_position_info.longitude;
		gnss_static_filter_buf.unit[gnss_static_filter_buf.cnt].direction   	= gnss_info_now.gnss_position_info.direction;
		gnss_static_filter_buf.cnt ++;
		if( gnss_static_filter_buf.cnt >= GNSS_STATIC_FILTER_BUF_SUM )			//缓冲区满，开始计算
		{
			for(i = 0; i < GNSS_STATIC_FILTER_BUF_SUM; i ++)					//将点数计数值清零
			{
				gnss_static_filter_buf.unit[i].density_cnt = 0;
				gnss_static_filter_buf.unit[i].angle_cnt   = 0;
			}
            
			for( i = 0; i < GNSS_STATIC_FILTER_BUF_SUM; i ++ )
			{
			    for( j = 0; j < GNSS_STATIC_FILTER_BUF_SUM; j ++ )
                {
                    distance = gnss_mileage_calculate( gnss_static_filter_buf.unit[i].lat, gnss_static_filter_buf.unit[i].lon ,gnss_static_filter_buf.unit[j].lat, gnss_static_filter_buf.unit[j].lon );
                    if( distance < 20 )
                    {   
                        gnss_static_filter_buf.unit[i].density_cnt ++;
                    }
                }
            }
                        
            density_cnt_max = 0;
			for( i = 0; i < GNSS_STATIC_FILTER_BUF_SUM; i ++ )					//找出周围20米内点数最多的点
			{
				if( gnss_static_filter_buf.unit[i].density_cnt > density_cnt_max )
				{
					density_cnt_max = gnss_static_filter_buf.unit[i].density_cnt;
				}
			}
			
			if( density_cnt_max > ( GNSS_STATIC_FILTER_BUF_SUM / 2 ) )		    //找到满足要求的点，更新数据并存储
			{
				for( i = 0; i < GNSS_STATIC_FILTER_BUF_SUM; i ++ )
				{
					if( density_cnt_max == gnss_static_filter_buf.unit[i].density_cnt   )
					{   
						lat_sum += gnss_static_filter_buf.unit[i].lat;
						lon_sum += gnss_static_filter_buf.unit[i].lon;
						cnt ++;
					}
				}
                
				gnss_info_now.gnss_position_info.latitude 	= lat_sum / cnt;   //满足点密度要求的点，经纬度分别求平均和
				gnss_info_now.gnss_position_info.longitude 	= lon_sum / cnt;
                gnss_info_now.gnss_position_info.speed = 0;					   //更新静态点，将GPS速度强制清零
				gnss_info_now.gnss_position_info.direction = 0;				   //更新静态点，将GPS航向角强制清零
				gnss_static_filter_buf.cnt = 0;								   //清除静态过滤缓冲区,重新取点，找定位点
                ret = pdPASS;
            }
			else
			{
				for(i = 0;i < GNSS_STATIC_FILTER_BUF_SUM; i++)
				{
					for(j = 0;j < GNSS_STATIC_FILTER_BUF_SUM; j++)
					{
					    direction = calculated_absolute_value(   gnss_static_filter_buf.unit[i].direction , gnss_static_filter_buf.unit[j].direction );
						if( (direction > 35) && (direction < 325) )  //周围夹角大于35度且小于325度的点的数目
						{
							gnss_static_filter_buf.unit[i].angle_cnt ++;
						}
					}
				}
                
				angle_cnt_max = 0;
				for(i = 0;i < GNSS_STATIC_FILTER_BUF_SUM ;i ++ )
				{
					if(gnss_static_filter_buf.unit[i].angle_cnt > angle_cnt_max)
					{
						angle_cnt_max = gnss_static_filter_buf.unit[i].angle_cnt;
					}
				}
				
				if( angle_cnt_max > ( GNSS_STATIC_FILTER_BUF_SUM / 4 ) )
				{
					for( i = 0;i < GNSS_STATIC_FILTER_BUF_SUM;i ++ )
					{
						if( angle_cnt_max == gnss_static_filter_buf.unit[i].angle_cnt )
						{
							lat_sum += gnss_static_filter_buf.unit[i].lat;
							lon_sum += gnss_static_filter_buf.unit[i].lon;
							cnt ++;
						}
					}
                    gnss_info_now.gnss_position_info.latitude   = lat_sum / cnt;    //满足点密度要求的点，经纬度分别求平均和
                    gnss_info_now.gnss_position_info.longitude  = lon_sum / cnt;
                    gnss_info_now.gnss_position_info.speed = 0;                    //更新静态点，将GPS速度强制清零
                    gnss_info_now.gnss_position_info.direction = 0;                //更新静态点，将GPS航向角强制清零
                    gnss_static_filter_buf.cnt = 0;                                //清除静态过滤缓冲区,重新取点，找定位点
                    ret = pdPASS;
                }
				else
				{
					gnss_static_filter_buf.cnt = 0;								  //清除静态过滤缓冲区,重新取点，找定位点
                    ret = pdFAIL;
                }
			}
		}
		else
		{
		    ret = pdFAIL;
		}
	}
	else
	{
	    ret = pdFAIL;
	}
    
    return ret;
}

/** ****************************************************************************
* @remarks       uint32_t gnss_speed_get( uint32_t *speed )
* @brief         获取GNSS当前的速度
* @param[in]     无
* @param[out]    *speed 当前GNSS的速度 ,不能为空
* @return        pdPASS 数据有效 pdFAIL 数据无效 *speed 当前速度的指针
* @attention     无
*******************************************************************************/
uint32_t gnss_speed_get( uint32_t *speed )
{
    gnss_info_struct  info;
    if( speed == NULL )
    {
        return pdFAIL;
    }
    *speed = 0;
    gnss_info_now_get( &info );
    if( 0 == info.gnss_position_info.is_valid )
    {
        return pdFAIL;
    }
    *speed = info.gnss_position_info.speed;
    return pdPASS;
}

/** ****************************************************************************
* @remarks       uint32_t gnss_mileage_get( void )
* @brief         获取GNSS 计算累积里程
* @param[in]     无
* @param[out]    无
* @return        GNSS里程 单位，米
* @attention     无
*******************************************************************************/
uint32_t gnss_mileage_get( void )
{
    return gnss_driving_mileage;
}

/** ****************************************************************************
* @remarks       void gnss_mileage_set( void )
* @brief         设置GNSS 计算累积里程
* @param[in]     mil  设置当前车辆运行的距离，单位米
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
void gnss_mileage_set( uint32_t mil )
{
    gnss_save_info_t save_infor = { 0 };
    
    gnss_info_mutex_take();
    gnss_driving_mileage = mil;
    save_infor.lat = gnss_info_old.gnss_position_info.latitude;
    save_infor.lng = gnss_info_old.gnss_position_info.longitude;
    save_infor.mil = mil;
    save_infor.crc = calculate_crc32( CRC_INIT , (uint8_t *)&save_infor , ( sizeof( gnss_save_info_t ) -4 ));
    gnss_save_info_flash_write( save_infor );
    gnss_info_mutex_give();
}

/** ****************************************************************************
* @remarks       uint32_t gnss_status_get( void )
* @brief         获取GNSS模块的状态
* @param[in]     无
* @param[out]    无
* @return        GNSS_ANT_ERR 天线异常  GNSS_MOD_OK 模块正常 GNSS_POS_OK 定位正常
* @attention     无
*******************************************************************************/
uint32_t gnss_status_get( void )
{
    uint32_t i = GNSS_STA_INIT;
    
    gnss_info_mutex_take();
#if 0    
    if( gnss_info_now.gnss_ant_status != GPS_ANT_OK )
    {
        i = GNSS_MON_ERR;
    }
    else if( gnss_info_now.gnss_model_status == GPS_MODEL_OK )
    {
        i = GNSS_MOD_OK;
    }
    else if( gnss_info_now.gnss_model_status == GPS_MODEL_ERROR )
    {
        i = GNSS_MON_ERR;
    }
#endif
    if( gnss_info_now.gnss_model_status == GPS_MODEL_OK )               // GPS模块正常
    {
        i = GPS_MODEL_OK;
    }
    else if( gnss_info_now.gnss_model_status == GPS_MODEL_ERROR )       // GPS模块故障
    {
        i = GPS_MODEL_ERROR;
    }   
    else if( gnss_info_now.gnss_model_status == GPS_MODEL_DATA_ERROR )  // GPS模块数据异常
    {
        i = GPS_MODEL_DATA_ERROR;
    }
    else if( gnss_info_now.gnss_model_status == GPS_MODEL_POSI_ERROR )  // GPS模块定位异常
    {
        i = GPS_MODEL_POSI_ERROR;
    }
    else if( gnss_info_now.gnss_model_status == GPS_MODEL_POSI_OK )     // GPS模块定位成功
    {
        i = GPS_MODEL_POSI_OK;
    }

    if( gnss_info_now.gnss_position_info.pos_flag == 1 )
    {
        i = GPS_MODEL_POSI_OK;
    }
    gnss_info_mutex_give();
    
    return i;
}

/** ****************************************************************************
* @remarks       uint8_t gnss_agps_num_get( void )
* @brief         获取AGPS辅助卫星数量
* @param[in]     无
* @param[out]    无
* @return        卫星数量
* @attention     无
*******************************************************************************/
uint8_t gnss_agps_num_get( void )
{
    return gnss_info_now.gnss_position_info.agps_num;
}

/** ****************************************************************************
* @remarks       uint32_t gnss_ant_atate_get( void )
* @brief         获取GNSS模块天线的状态
* @param[in]     无
* @param[out]    无
* @return        GPS_ANT_OK GPS天线正常 ， GPS_ANT_SHORT GPS天线短路 ，GPS_ANT_OPEN GPS天线断路 ，PS_ANT_FAULT GPS天线故障 ，PS_ANT_NOT_Stability GPS天线状态不稳定 AD数据连续采样不一致。
* @attention     无
*******************************************************************************/
uint32_t gnss_ant_atate_get( void )
{
    return ( GPS_ANT_OK );
}

/** ****************************************************************************
* @remarks       static void gnss_antenna_status_query(void)
* @brief         获取GNSS天线的状态
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void gnss_antenna_status_query(void)
{
    gnss_info_mutex_take();
    gnss_info_now.gnss_ant_status = gnss_ant_atate_get(); /*获取GNSS外部天线状态*/
    gnss_info_mutex_give();
}

/** ****************************************************************************
* @remarks       uint32_t gnss_static_filter_count_get( void )
* @brief         获取GNSS 静态数据过滤次数
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
uint32_t gnss_static_filter_count_get( void )
{
    return gnss_static_filter_count;
}

/** ****************************************************************************
* @remarks       void gnss_sys_time_set( void )
* @brief         获取GNSS 时间 设置系统时间
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
void gnss_sys_time_set( void )
{   
    rtc_struct rtc = { 0 };
    
    rtc.year = gnss_info_now.gnss_position_info.time.year + 0x2000;
    rtc.month = gnss_info_now.gnss_position_info.time.month;
    rtc.day = gnss_info_now.gnss_position_info.time.day;
    rtc.hour = gnss_info_now.gnss_position_info.time.hour;
    rtc.minute = gnss_info_now.gnss_position_info.time.minute;
    rtc.second = gnss_info_now.gnss_position_info.time.second;
    rtc_bcd_to_int( &rtc );
    rtc_utc_to_local( &rtc , GN_LOCAL );      /*转变为北京时间*/
    rtc_sys_set( RTC_TIM_CAL_INT, &rtc );
    
}
/** ****************************************************************************
* @remarks       void gnss_info_now_get( gnss_info_struct *info )
* @brief         获取GNSS最新数据数据信息
* @param[in]     无
* @param[out]    *info GNSS数据的目标地址
* @return        无
* @attention     无
*******************************************************************************/
void gnss_info_now_get( gnss_info_struct *info )
{
    gnss_info_mutex_take();
    memcpy(( uint8_t * )info, ( uint8_t * )&gnss_info_old, sizeof( gnss_info_struct ) );
    gnss_info_mutex_give();
}
/** ****************************************************************************
* @remarks       void gnss_info_old_get( gnss_info_struct *info )
* @brief         获取GNSS历史数据
* @param[in]     无
* @param[out]    *info GNSS数据的目标地址
* @return        无
* @attention     无
*******************************************************************************/
void gnss_info_old_get( gnss_info_struct *info )
{
    gnss_info_mutex_take();
    memcpy(( uint8_t * )info, ( uint8_t * )&gnss_info_old, sizeof( gnss_info_struct ) );
    gnss_info_mutex_give();
}

/** ****************************************************************************
* @remarks       void gnss_info_flash_read( void )
* @brief         获取GNSS FLASH 存储的数据
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
void gnss_info_flash_read( gnss_info_struct *gnss )
{
    uint32_t num = 0 , handle_num = 0;
    uint32_t gnss_addr = 0, gnss_block = 0;
    gnss_save_info_t gnss_infor = { 0 };
    /*查找数据块中第一条数据是否符合校验*/
    memset( (uint8_t *)gnss, 0x00, sizeof( gnss_info_struct ) );
    
    /*查找写入的FLASH块数据*/
    for( num = 0 ; num < SF_GNSS_DATA_FlAG_SECTORS ; num ++ )
    {
        gnss_block = SF_GNSS_DATA_ADDR + num * SPI_FLASH_MIN_SECTOR;
        if( pdPASS ==  sfb_read_buf( gnss_block, (uint8_t* )&gnss_infor, sizeof(gnss_save_info_t)) )
        {
            if( gnss_infor.crc != calculate_crc32( CRC_INIT, (uint8_t *)&gnss_infor , sizeof(gnss_save_info_t) - sizeof(uint32_t) ) )
            {
                break;
            }
        }
        else
        {
            break;
        }
    }
    
    if( num != 0 )
    {
        gnss_block = SF_GNSS_DATA_ADDR + ( num - 1 ) * SPI_FLASH_MIN_SECTOR;
        gnss_data_save_location = ( num - 1 ) * SPI_FLASH_MIN_SECTOR / sizeof(gnss_save_info_t);
        handle_num = SPI_FLASH_MIN_SECTOR / sizeof(gnss_save_info_t);
        for( num = 0 ; num < handle_num; num ++ )
        {
            gnss_addr = gnss_block + ( num * sizeof(gnss_save_info_t) );
            if( pdPASS ==  sfb_read_buf( gnss_addr, (uint8_t* )&gnss_infor, sizeof(gnss_save_info_t)))
            {
                if( gnss_infor.crc == calculate_crc32( CRC_INIT, (uint8_t *)&gnss_infor , sizeof(gnss_save_info_t) - sizeof(uint32_t) ) )
                {
                    gnss_data_save_location++;
                    gnss->gnss_position_info.latitude = gnss_infor.lat;
                    gnss->gnss_position_info.longitude = gnss_infor.lng;
                    gnss_driving_latitude = gnss_infor.lat;
                    gnss_driving_longitude = gnss_infor.lng;
                    gnss_driving_mileage =   gnss_infor.mil;
                }
                else
                {
                    break;
                }
            }
            else
            {
                break;
            }
        }
    }
}

/** ****************************************************************************
* @remarks       void gnss_info_flash_read( void )
* @brief         获取GNSS FLASH 存储的数据
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
void gnss_info_flash_write( void )
{
    static gnss_save_info_t save_info = { 0 };

    save_info.lat = gnss_info_old.gnss_position_info.latitude;      /*纬度*/
    save_info.lng = gnss_info_old.gnss_position_info.longitude;     /*经度*/
    save_info.mil = gnss_driving_mileage;                           /*累计里程*/
    /*计算CRC*/
    save_info.crc = calculate_crc32( CRC_INIT , (uint8_t *)&save_info , ( sizeof( gnss_save_info_t ) -4 ));
    /*保存数据*/
    gnss_data_save_location = 0;
    
    gnss_save_info_flash_write( save_info );
#if( GNSS_QXWZ == 1 )
    /*系统复位之前将GPS数据进行保存*/
    qxwz_inject_gpdrc_4_flash_write( gnss_gpdrc_data_buf, gnss_gpdrc4_data_buf );
#endif
}

/** ****************************************************************************
* @remarks       gnss_static_filter_enable_state_e gnss_static_filter_enable_state_get( void ) 
* @brief         获取GNSS 静止数据过滤使能状态
* @param[in]     无
* @param[out]    无
* @return        返回使能状态  GNSS_SF_ENABLE 使能， GNSS_SF_DISENABLE 失能
* @attention     无
*******************************************************************************/
gnss_static_filter_enable_state_e gnss_static_filter_enable_state_get( void ) 
{
    return gnss_static_filter_enable_st;
}

/** ****************************************************************************
* @remarks       void gnss_static_filter_enable_state_get( gnss_static_filter_enable_state_e st ) 
* @brief         设置GNSS 静止数据过滤使能状态
* @param[in]     st设置使能状态；GNSS_SF_ENABLE 使能， GNSS_SF_DISENABLE 失能
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
void gnss_static_filter_enable_state_set( gnss_static_filter_enable_state_e st ) 
{
    gnss_static_filter_enable_st = st;
}

/** ****************************************************************************
* @remarks       static void gnss_save_info_flash_write( gnss_save_info_t gnss_infor )
* @brief         保存GNSS 当前的固定位置存储的数据
* @param[in]     gnss_infor 保存数据
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void gnss_save_info_flash_write( gnss_save_info_t gnss_infor )
{
    uint32_t gnss_addr = SF_GNSS_DATA_ADDR , i = 0 , ret = pdFAIL;
    gnss_save_info_t gnss_infor_read = { 0 };
    
    if( gnss_data_save_location == 0 )
    {
        sfb_block_reset( SF_GNSS_DATA_ADDR, SF_GNSS_DATA_FlAG_SECTORS );
    }
    gnss_addr += gnss_data_save_location * sizeof(gnss_save_info_t);
    if( gnss_addr >= ( SF_GNSS_DATA_ADDR + SF_GNSS_DATA_SIZE ) )
    {
        gnss_addr = SF_GNSS_DATA_ADDR;
    }
    for( i = 0 ; i < 3 ; i ++ )
    {
        if( sfb_write_buf(  gnss_addr, ( uint8_t* )&gnss_infor, sizeof(gnss_save_info_t) ) == pdPASS )
        {
            if( pdPASS ==  sfb_read_buf( gnss_addr, (uint8_t* )&gnss_infor_read, sizeof(gnss_save_info_t)) )
            {
                if( gnss_infor.crc == calculate_crc32( CRC_INIT, (uint8_t *)&gnss_infor_read , sizeof(gnss_save_info_t) - sizeof(uint32_t) ) )
                {
                    ret = pdPASS;
                    break;
                }
            }
        }
    }
    
    if( ret == pdPASS  )
    {
        gnss_data_save_location ++;
        if( gnss_data_save_location >= ( SF_GNSS_DATA_SIZE / sizeof(gnss_save_info_t) ) )
        {
            gnss_data_save_location = 0;
        }
    }
    else
    {
        gnss_data_save_location = 0;
        sfb_block_reset( SF_GNSS_DATA_ADDR, SF_GNSS_DATA_FlAG_SECTORS );
        gnss_addr = SF_GNSS_DATA_ADDR;
        sfb_write_buf(  gnss_addr, ( uint8_t* )&gnss_infor, sizeof(gnss_save_info_t) );
    }
}

/** ****************************************************************************
* @remarks       static uint32_t gnss_data_task_par_init( void )
* @brief         GNSS数据处理任务参数初始化
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static uint32_t gnss_data_task_par_init( void )
{
    gnss_invalid_time = gaoz_get_systick();
    gnss_invalid_data_time = gaoz_get_systick();
    gnss_invalid_speed_count = 0;
    gnss_valid_speed_count = 0;
    gnss_invalid_location_time = gaoz_get_systick();
    gnss_static_filter_buf.cnt = 0;
    gnss_set_time_tick = gaoz_get_systick(); /*获取当前最新的系统时钟*/
    memset( (uint8_t *)gnss_gpdrc_data_buf, 0x00, GNSS_GPDRC_DATA_LEN );
    memset( (uint8_t *)gnss_gpdrc4_data_buf, 0x00, GNSS_GPDRC4_DATA_LEN );
    return 0;
}

/** ****************************************************************************
* @remarks       static void gnss_invalid_time_reg_init(void)
* @brief         GNSS 数据无效时间定时器初始化
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void gnss_invalid_time_reg_init(void)
{
    gnss_invalid_time = gaoz_get_systick();    /*获取当前最新的系统时钟*/
}

/** ****************************************************************************
* @remarks       static void gnss_invalid_time_reg_init(void)
* @brief         GNSS数据无效时寄存器计数
* @param[in]     无
* @param[out]    无
* @return        pdPASS 计数时间溢出 ， pdFAIL 计数时间无效
* @attention     计数时间设置 GNSS_INVALID_TIEER 
*******************************************************************************/
static uint32_t gnss_invalid_time_reg_count(void)
{
    uint32_t ret = pdFAIL;

    if( pdPASS == sys_timestamp_delay(( uint32_t * )&gnss_invalid_time, GNSS_INVALID_TIEER ) )
    {
        ret = pdPASS;
    }
    return ret;
}
/** ****************************************************************************
* @remarks       static void gnss_invalid_data_reg_init(void)
* @brief         GNSS数据无效寄存器初始化
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void gnss_invalid_data_reg_init(void)
{
    gnss_invalid_data_time = gaoz_get_systick();    /*获取当前最新的系统时钟*/
}

/** ****************************************************************************
* @remarks       static uint8_t gnss_invalid_data_count(void)
* @brief         GNSS数据无效寄存器计数
* @param[in]     无
* @param[out]    无
* @return        pdPASS 计数时间溢出 ， pdFAIL 计数时间无效
* @attention     计数时间设置 GNSS_NO_DATA_TIEER
*******************************************************************************/
static uint8_t gnss_invalid_data_count(void)
{
    uint8_t ret = pdFAIL;

    if( pdPASS == sys_timestamp_delay(( uint32_t * )&gnss_invalid_data_time, GNSS_NO_DATA_TIEER ) )
    {
        ret = pdPASS;
    }
    return ret;
}

/** ****************************************************************************
* @remarks       static void gnss_invalid_location_reg_init(void)
* @brief         GNSS无效定位寄存器初始化
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void gnss_invalid_location_reg_init(void)
{
    gnss_invalid_location_time = gaoz_get_systick();    /*获取当前最新的系统时钟*/
}

/** ****************************************************************************
* @remarks       static uint8_t gnss_invalid_location_count(void)
* @brief         GNSS无效定位寄存器计数
* @param[in]     无
* @param[out]    无
* @return        pdPASS 计数时间溢出 ， pdFAIL 计数时间无效
* @attention     计数时间设置 GNSS_INVALID_LOC_TIEER
*******************************************************************************/
static uint8_t gnss_invalid_location_count(void)
{
    uint8_t ret = pdFAIL;

    if( pdPASS == sys_timestamp_delay(( uint32_t * )&gnss_invalid_location_time, GNSS_INVALID_LOC_TIEER ) )
    {
        ret = pdPASS;
    }
    return ret;
}


/** ****************************************************************************
* @remarks       static void gnss_debug_print_fun( uint8_t * data , uint16_t len )
* @brief         GNSS数据打印
* @param[in]     * data打印数据源地址
* @param[in]     len 打印数据长度
* @param[out]    无
* @return        无
* @attention     计数时间设置 GNSS_INVALID_LOC_TIEER
*******************************************************************************/
static void gnss_debug_print_fun( uint8_t * data , uint16_t len )
{
    log_debug_send(DEBUG_MODE , GPS_MAN_NAME , data ,len );
}

/** ****************************************************************************
* @remarks       static void gnss_data_driver_close( void )
* @brief         GNSS 底层关闭
* @param[in]     无
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void gnss_data_driver_close( void )
{   
#if( GNSS_QXWZ == 1 )
    qxwz_inject_sdk_stop();
#endif    
    //gaoz_hal_uart_deinit( GNSS_UART_PORT );
    gnss_module_power_control( GPS_MODEL_CLOSE );       /*关闭模块电源，重新启动*/
}

/** ****************************************************************************
* @remarks       static float gnss_mileage_calculate( uint32_t lat1, uint32_t lng1, uint32_t lat2, uint32_t lng2 ) 
* @brief         计算GNSS两点间的距离
* @param[in]     经纬度
* @param[out]    无
* @return        计算的距离单位，米
* @attention     无
*******************************************************************************/
static double radian(double d)
{
    #define PI  3.1415926
    return d * PI / 180.0;                  //角度1˚ = π / 180
}

static uint32_t gnss_mileage_calculate( uint32_t lat1, uint32_t lng1, uint32_t lat2, uint32_t lng2 ) 
{
    #define EARTH_RADIUS    6378.137        //地球近似半径
    #define MILES_KM        1.609344        //英里转变为公里
    
    double radLat1 = 0.0f, radLat2 = 0.0f;
    double a = 0.0f, b = 0.0f;
    double dst = 0.0f;
    double flat1 = 0.0f , flng1 = 0.0f , flat2 = 0.0f , flng2 = 0.0f ;
    uint32_t mil = 0;
    
    if(( lat1 == lat2 ) && ( lng1 == lng2 ))
    {
        return 0;
    }
    
    if(( lat1 == 0 ) || ( lng1 == 0 ) || ( lat2 == 0 ) || ( lng2 == 0 ))
    {
        return 0;
    }
    
    flat1 = lat1 / 1000000.0f;
    flng1 = lng1 / 1000000.0f;
    flat2 = lat2 / 1000000.0f;
    flng2 = lng2 / 1000000.0f;
    
    radLat1 = radian(flat1);
    radLat2 = radian(flat2);
    
    a = radLat1 - radLat2;
    b = radian(flng1) - radian(flng2);
    
    dst = 2 * asin((sqrt(pow(sin(a / 2), 2) + cos(radLat1) * cos(radLat2) * pow(sin(b / 2), 2) )));
    dst = dst * EARTH_RADIUS;
    
    dst= round(dst * 1000);  
    mil = ( uint32_t )( dst * MILES_KM );                  //英里转变为米
    
    return mil;
}

/** ****************************************************************************
* @remarks       static void gnss_mileage_data_update( void )
* @brief         GNSS 里程数据更新
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void gnss_mileage_data_update( void )
{
    #define GPS_SAVE_DATA_MIL ( 100 )
    static gnss_save_info_t save_info = { 0 };
    static uint32_t gnss_mil = 0;
    
    if( gnss_mil == 0 )
    {
        gnss_mil = gnss_driving_mileage;
    }
    gnss_driving_mileage += gnss_mileage_calculate( gnss_driving_latitude, gnss_driving_longitude ,gnss_info_old.gnss_position_info.latitude, gnss_info_old.gnss_position_info.longitude );
    gnss_driving_latitude = gnss_info_old.gnss_position_info.latitude;
    gnss_driving_longitude = gnss_info_old.gnss_position_info.longitude;
    //log_debug_printf(INFOR_MODE,GPS_MAN_NAME ,"gnss_mileage_data_update=%d\r\n", gnss_driving_mileage );
    if( gnss_driving_mileage > ( gnss_mil + GPS_SAVE_DATA_MIL ) )       /*记录行驶的GNSS距离*/
    {
        save_info.lat = gnss_info_old.gnss_position_info.latitude;      /*纬度*/
        save_info.lng = gnss_info_old.gnss_position_info.longitude;     /*经度*/
        save_info.mil = gnss_driving_mileage;                           /*累计里程*/
        gnss_mil = gnss_driving_mileage;
        /*计算CRC*/
        save_info.crc = calculate_crc32( CRC_INIT , (uint8_t *)&save_info , ( sizeof( gnss_save_info_t ) -4 ));
        /*保存数据*/
        log_debug_printf(INFOR_MODE,GPS_MAN_NAME ,"GNSS calculates total mileage=%d\r\n", gnss_driving_mileage );
        gnss_save_info_flash_write( save_info );
    }
}
#if( GNSS_QXWZ == 1 )
/** ****************************************************************************
* @remarks       static uint32_t gnss_basic_data_filtering( gnss_recv_buf_typedef * msg )
* @brief         GNSS 基础数据过滤
* @param[in]     无
* @param[out]    无
* @return        pdPASS 获取数据成功 ， pdFAIL 获取数据失败
* @attention     函数的功能是将数据填充到 gnss_nmea_data 结构体中
*******************************************************************************/
static uint32_t gnss_basic_data_filtering( gnss_recv_buf_typedef * msg )
{
    uint32_t ret = pdFAIL;
    uint8_t i = 0;
    char *position = NULL;
    uint16_t plen = 0;

    /*清空数据接收空间*/
    memset((uint8_t *)gnss_nmea_data.data , 0x00 ,GNSS_NMEA_DATA_LEN );
    gnss_nmea_data.len = 0;
    /*解析GNSS数据头信息*/
    for( i = 0 ; i < NMEA_TYPE_LEN ; i ++ )
    {
        position = mstrnstr(( const char* )msg->data ,msg->len, ( const char* )nmea_pheads[i] ,6 );
        if( position != NULL )
        {
            plen = mstrnlens( (const char *)position, '\r', msg->len ); /*查找回车字符*/
            if( plen != 0 )
            {
                #if 0
                log_debug_send(DEBUG_MODE,GPS_MAN_NAME ,position,plen);
                #endif
                if( gnss_nmea_data.len < GNSS_NMEA_DATA_LEN ) /*数据空间地址长度保护*/
                {
                    memcpy((uint8_t *)&gnss_nmea_data.data[gnss_nmea_data.len] , position , plen );
                    gnss_nmea_data.len  += plen;
                    gnss_nmea_data.data[gnss_nmea_data.len] ='\r';
                    gnss_nmea_data.len ++;
                    gnss_nmea_data.data[gnss_nmea_data.len] ='\n';
                    gnss_nmea_data.len ++;
                    ret = pdPASS;
                }
            }
        }
    }
    
    return ret;
}
#endif


/** ****************************************************************************
* @remarks       static void gnss_lbs_wifiscan_data_cb( uint8_t type, uint32_t latitude, uint32_t longitude )
* @brief         LBS wifiscan 辅助定位数据回调函数
* @param[in]     type: 定位类型，0:没有得到定位结果;1:gps 定位结果;2:wifi定位结果;3:混合定位 结果;4:基站定位结果;5:其他--
                 latitude: 纬度，正数为北纬，精确到0.00001分
                 longitude: 经度，正数为东经，精确到0.00001分
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void gnss_lbs_wifiscan_data_cb( uint8_t type, uint32_t latitude, uint32_t longitude )
{
    // gnss_lbs_position_new_state = LBS_ONLY_READ;
    // gnss_lbs_position_type = 0x04;// 基站定位结果
    // gnss_info_old.gnss_position_info.pos_flag = 1;//定位设置为有效
   
    if( type != 0 )
    {
          log_debug_printf(DEBUG_MODE , GPS_MAN_NAME ,"gnss_lbs_position_new_state = LBS_ONLY_READ\r\n" ,0);
        gnss_lbs_position_new_state = type;
        gnss_lbs_position_type = type;
        gnss_lbs_position_once_state = type;
        gnss_info_old.gnss_position_info.is_lbs_type = type; 
        gnss_info_old.gnss_position_info.latitude = latitude;
        gnss_info_old.gnss_position_info.pos_flag = 1;
        gnss_info_old.gnss_position_info.longitude = longitude;
        /*LBS数据更新成功后，需要对点位数据读取一次*/
        gnss_mileage_data_update();
    }
    log_debug_printf(DEBUG_MODE , GPS_MAN_NAME ,"GNSS LBS position : type = %d,lat = %ld, lon = %ld" ,type, latitude, longitude );
}

/** ****************************************************************************
* @remarks       static void gnss_lbs_wifiscan_position_read( void )
* @brief         LBS wifiscan 辅助定位数据读取
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
void gnss_lbs_wifiscan_position_read( void )
{
    if( gnss_info_now.gnss_position_info.pos_flag == 0 )    /*GNSS定位数据无效*/
    {
        lbs_wifiscan_coordinate_position_read( LBS_ONLY_READ, 0, gnss_lbs_wifiscan_data_cb );
    }
    else
    {
        gnss_lbs_position_type = 0;
    }
    gnss_lbs_position_once_state = 0x00;
}

/** ****************************************************************************
* @remarks       uint8_t gnss_lbs_position_type_read( void )
* @brief         GNSS LBS 辅助定位类型
* @param[in]     无
* @param[out]    无
* @return        定位类型，0:没有得到定位结果;1:gps 定位结果;2:wifi定位结果;3:混合定位 结果;4:基站定位结果;5:其他--
* @attention     无
*******************************************************************************/
uint8_t gnss_lbs_position_type_read( void )
{           
    return gnss_lbs_position_type;
}

/** ****************************************************************************
* @remarks       void gnss_lbs_position_type_clear( void )
* @brief         清除掉 GNSS LBS 辅助定位类型标识
* @param[in]     无
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
void gnss_lbs_position_type_clear( void )
{           
    gnss_lbs_position_type = 0;
}

uint8_t gnss_lbs_position_once_state_read( void )
{
    return gnss_lbs_position_once_state;
}

uint8_t gnss_lbs_position_new_state_get(void)
{
    return gnss_lbs_position_new_state;
}

void gnss_lbs_position_new_state_set(uint8_t newState)
{
    gnss_lbs_position_new_state = newState;  
}


#if( OS_GNSS_MODULE_TYPE == 1 ) /*选择GNSS型号为中科微，通信波特率为115200*/
void gnss_baud_rate_switching( void )
{
    #define GNSS_BAUD_RATE_9600     "$PCAS01,1*1D\r\n"
    #define GNSS_BAUD_RATE_115200   "$PCAS01,5*19\r\n"
    #define GNSS_AGPS_TXT_SET       "$PCAS03,,,,,,,,,,,1*1F\r\n"
    /*使用9600波特率设置GNSS模块通信速率为115200*/
    gaoz_task_sleep( 500 );
    gnss_hal_uart_init( 9600 );
    gaoz_hal_uart_put( GNSS_UART_PORT, (uint8_t *)GNSS_BAUD_RATE_115200, sizeof( GNSS_BAUD_RATE_115200 ) );
    /*使用115200波特率设置GNSS模块AGPS TXT报文输出*/
    gaoz_task_sleep( 500 );
    gnss_hal_uart_init( 115200 );
    gaoz_hal_uart_put( GNSS_UART_PORT, (uint8_t *)GNSS_AGPS_TXT_SET, sizeof( GNSS_AGPS_TXT_SET ) );
}
#endif
/** ****************************************************************************
* @remarks       static uint32_t gnss_task_into_run_mode(void)
* @brief         GNSS任务进入运行状态
* @param[in]     无
* @param[out]    无
* @return        pdPASS 设置成功 pdFAIL 设置失败
* @attention     无
*******************************************************************************/
static uint32_t gnss_task_into_run_mode(void)
{
    task_modules_e state = TASK_MODE_INIT;
    uint32_t ret = pdFAIL; 
    state = power_man_save_state_get( gnss_power_man_id );                  /*获取任务的运行状态*/
    if( state != TASK_RUN_MODE )
    {   
        //gnss_hal_uart_init();                                               /*初始化GNSS底层驱动串口*/
        ret = gnss_module_power_control( GPS_MODEL_OPEN );                  /*打开模块电源*/
        if( ret == pdPASS )
        {
        #if( GNSS_GEMU == 1 )
            power_man_save_state_set( gnss_power_man_id ,TASK_RUN_MODE );
            gnss_set_time_tick = gaoz_get_systick();                    /*获取当前最新的系统时钟*/
            log_debug_send(INFOR_MODE,GPS_MAN_NAME ,"<<<<<<<<<<*****GNSS task enters RUN mode*****>>>>>>>>>>\r\n", 0);
        #if( OS_GNSS_MODULE_TYPE != 1 )    
            agnss_data_timestamp_set( AGNSS_RUN_TIMESTAMP );            /*GNSS 运行后，设置AGNSS获取数据的时间戳*/
        #endif
            gnss_invalid_time_reg_init();
            gnss_invalid_data_reg_init();
            gnss_invalid_location_reg_init();
        #if( OS_GNSS_MODULE_TYPE == 1 ) /*选择GNSS型号为中科微，通信波特率为115200*/
            gnss_baud_rate_switching();
        #endif
        #endif
        #if( GNSS_QXWZ == 1 )
            if( qxwz_inject_cfg_parameter_status_get() != pdPASS )                  /*获取千寻SDK 参数配置状态*/
            {
                log_debug_printf(INFOR_MODE, GPS_MAN_NAME, "QXWZ network server parameters read invalid,gnss_qxsdk_enable_st = GNSS_QXSDK_DISENABLE\r\n" );
                gnss_qxsdk_enable_st = GNSS_QXSDK_DISENABLE;
                power_man_save_state_set( gnss_power_man_id ,TASK_RUN_MODE );
                gnss_set_time_tick = gaoz_get_systick();                            /*获取当前最新的系统时钟*/
                log_debug_send(INFOR_MODE,GPS_MAN_NAME ,"<<<<<<<<<<*****GNSS task enters RUN mode*****>>>>>>>>>>\r\n", 0);
                gnss_invalid_time_reg_init();
                gnss_invalid_data_reg_init();
                gnss_invalid_location_reg_init();
                ret = pdPASS;
            }
            else
            {
                gaoz_task_sleep( 100 );                                                 /*延时100mS钟等待硬件稳定*/
                if( qxwz_inject_gpdrc_4_flash_read( gnss_gpdrc_data_buf, gnss_gpdrc4_data_buf ) == pdPASS )
                {
                    log_debug_send(INFOR_MODE,GPS_MAN_NAME ,"QXWZ gpdrc and gpdrc4 reading data successfully\r\n", 0);
                }
                qxwz_inject_para_init( gnss_data_update_buf, gnss_gpdrc_data_buf, gnss_gpdrc4_data_buf );   /*初始化千寻SDK，可以重复进行初始化操作*/
                if( qxwz_inject_sdk_start() == pdPASS )                                /*启动千寻网络*/
                {
                    log_debug_printf(INFOR_MODE, GPS_MAN_NAME, "QXWZ network server parameters read valid,gnss_qxsdk_enable_st = GNSS_QXSDK_ENABLE\r\n" );
                    gnss_qxsdk_enable_st = GNSS_QXSDK_ENABLE;
                    qxwz_inject_gpdrc_4_flash_clear();                                  
                    memset((uint8_t *)gnss_gpdrc_data_buf, 0x00, GNSS_GPDRC_DATA_LEN ); /*设置成功后，将GPDRC数据清空防止出现数据二次使用*/
                    memset((uint8_t *)gnss_gpdrc4_data_buf, 0x00, GNSS_GPDRC4_DATA_LEN ); /*设置成功后，将GPDRC4数据清空防止出现数据二次使用*/
                    power_man_save_state_set( gnss_power_man_id ,TASK_RUN_MODE );
                    gnss_set_time_tick = gaoz_get_systick();                            /*获取当前最新的系统时钟*/
                    log_debug_send(INFOR_MODE,GPS_MAN_NAME ,"<<<<<<<<<<*****GNSS task enters RUN mode*****>>>>>>>>>>\r\n", 0);
                    gnss_invalid_time_reg_init();
                    gnss_invalid_data_reg_init();
                    gnss_invalid_location_reg_init();
                    ret = pdPASS;
                } 
            }
        #endif
        }
    }
    else if( state == TASK_RUN_MODE )
    {
        ret = pdPASS;
    }
    return ret;
}
/** ****************************************************************************
* @remarks       static uint32_t gnss_task_into_sleep_mode(void)
* @brief         GNSS任务进入睡眠状态
* @param[in]     无
* @param[out]    无
* @return        pdPASS 设置成功 pdFAIL 设置失败
* @attention     无
*******************************************************************************/
static uint32_t gnss_task_into_sleep_mode(void)
{
    task_modules_e state = TASK_MODE_INIT;
    uint32_t ret = pdFAIL; 
    state = power_man_save_state_get( gnss_power_man_id );   /*获取任务的运行状态*/
    if( state != TASK_SLEEP_MODE )
    {       
    #if( GNSS_GEMU == 1 )
        ret = gnss_module_power_control( GPS_MODEL_CLOSE ); /*关闭模块电源*/
        if( ret == pdPASS )
        {
            //gaoz_hal_uart_deinit( GNSS_UART_PORT );
            gnss_static_filter_enable_state_set( GNSS_SF_DISENABLE );   /*当GNSS处于休眠状态时，GNSS静止数据过滤状态失能*/
            power_man_save_state_set( gnss_power_man_id ,TASK_SLEEP_MODE );
            log_debug_send(INFOR_MODE,GPS_MAN_NAME ,"<<<<<<<<<<*****GNSS task enters SLEEP mode*****>>>>>>>>>>\r\n", 0);
        #if( OS_GNSS_MODULE_TYPE != 1 )
            agnss_data_timestamp_set( AGNSS_SLEEP_TIMESTAMP );          /*GNSS 休眠后，设置AGNSS获取数据的时间戳*/
        #endif
        }
    #endif
    #if( GNSS_QXWZ == 1 )
        if( qxwz_inject_cfg_parameter_status_get() != pdPASS )   
        {
            gnss_static_filter_enable_state_set( GNSS_SF_DISENABLE );   /*当GNSS处于休眠状态时，GNSS静止数据过滤状态失能*/
            power_man_save_state_set( gnss_power_man_id ,TASK_SLEEP_MODE );
            log_debug_send(INFOR_MODE,GPS_MAN_NAME ,"<<<<<<<<<<*****GNSS task enters SLEEP mode*****>>>>>>>>>>\r\n", 0);
            ret = pdPASS;
        }
        else
        {
            ret = qxwz_inject_sdk_stop();                             /*停止千寻网络*/ 
            if( ret == pdPASS )
            {
                ret = gnss_module_power_control( GPS_MODEL_CLOSE ); /*关闭模块电源*/
                if( ret == pdPASS )
                {
                    //gaoz_hal_uart_deinit( GNSS_UART_PORT );
                    if( qxwz_inject_gpdrc_4_flash_write( gnss_gpdrc_data_buf, gnss_gpdrc4_data_buf ) == pdPASS )
                    {
                        log_debug_send(INFOR_MODE,GPS_MAN_NAME ,"QXWZ gpdrc and gpdrc4 writer data successfully\r\n", 0);
                    }
                    gnss_static_filter_enable_state_set( GNSS_SF_DISENABLE );   /*当GNSS处于休眠状态时，GNSS静止数据过滤状态失能*/
                    power_man_save_state_set( gnss_power_man_id ,TASK_SLEEP_MODE );
                    log_debug_send(INFOR_MODE,GPS_MAN_NAME ,"<<<<<<<<<<*****GNSS task enters SLEEP mode*****>>>>>>>>>>\r\n", 0);
                }
            } 
        }  
    #endif
    }
    else if( state == TASK_SLEEP_MODE )
    {
        ret = pdPASS;
    }
    return ret;
}

/** ****************************************************************************
* @remarks       static uint32_t gnss_task_into_sleep_mode(void)
* @brief         GNSS任务进入停止状态
* @param[in]     无
* @param[out]    无
* @return        pdPASS 设置成功 pdFAIL 设置失败
* @attention     无
*******************************************************************************/
static uint32_t gnss_task_into_stop_mode(void)
{
    task_modules_e state = TASK_MODE_INIT;
    uint32_t ret = pdFAIL; 
    state = power_man_save_state_get( gnss_power_man_id );  /*获取任务的运行状态*/
    if( state != TASK_STOP_MODE )
    {   
    #if( GNSS_GEMU == 1 )
        ret = gnss_module_power_control( GPS_MODEL_CLOSE );     /*关闭模块电源*/
        if( ret == pdPASS )
        {
            //gaoz_hal_uart_deinit( GNSS_UART_PORT );
            gnss_static_filter_enable_state_set( GNSS_SF_DISENABLE );   /*当GNSS处于休眠状态时，GNSS静止数据过滤状态失能*/
            power_man_save_state_set( gnss_power_man_id ,TASK_STOP_MODE );
            log_debug_send(INFOR_MODE,GPS_MAN_NAME ,"<<<<<<<<<<*****GNSS task enters STOP mode*****>>>>>>>>>>\r\n", 0);
        #if 0
            agnss_data_timestamp_set( AGNSS_SLEEP_TIMESTAMP );    /*GNSS 休眠后，设置AGNSS获取数据的时间戳*/
        #endif
        }
    #endif
    #if( GNSS_QXWZ == 1 )
        if( qxwz_inject_cfg_parameter_status_get() != pdPASS )   
        {
            gnss_static_filter_enable_state_set( GNSS_SF_DISENABLE );   /*当GNSS处于休眠状态时，GNSS静止数据过滤状态失能*/
            power_man_save_state_set( gnss_power_man_id ,TASK_STOP_MODE );
            log_debug_send(INFOR_MODE,GPS_MAN_NAME ,"<<<<<<<<<<*****GNSS task enters STOP mode*****>>>>>>>>>>\r\n", 0);
            ret = pdPASS;
        }
        else
        {
            ret = qxwz_inject_sdk_stop();                           /*停止千寻网络*/ 
            if( ret == pdPASS )
            {
                ret = gnss_module_power_control( GPS_MODEL_CLOSE );     /*关闭模块电源*/
                if( ret == pdPASS )
                {   
                    //gaoz_hal_uart_deinit( GNSS_UART_PORT );
                    if( qxwz_inject_gpdrc_4_flash_write( gnss_gpdrc_data_buf, gnss_gpdrc4_data_buf ) == pdPASS )
                    {
                        log_debug_send(INFOR_MODE,GPS_MAN_NAME ,"QXWZ gpdrc and gpdrc4 writer data successfully\r\n", 0);
                    }
                    gnss_static_filter_enable_state_set( GNSS_SF_DISENABLE );   /*当GNSS处于休眠状态时，GNSS静止数据过滤状态失能*/
                    power_man_save_state_set( gnss_power_man_id ,TASK_STOP_MODE );
                    log_debug_send(INFOR_MODE,GPS_MAN_NAME ,"<<<<<<<<<<*****GNSS task enters STOP mode*****>>>>>>>>>>\r\n", 0);
                }
            } 
        }
   #endif
    }
    else if( state == TASK_STOP_MODE )
    {
        ret = pdPASS;
    }
    return ret;
}

/** ****************************************************************************
* @remarks       static void gnss_data_handle_task( void * pvParameters )
* @brief         GNSS基础数据处理任务
* @param[in]     * pvParameters 任务参数
* @param[out]    无
* @return        无
* @attention     无
*******************************************************************************/
static void gnss_data_handle_task( void * pvParameters )
{
    ( void ) pvParameters;
    #define GPS_SET_TIME_PERIOD ( 3600 * GAOZ_TICK_PERIOD_S )                        /*设置时间为1小时*/
    task_modules_e gnss_run_st;
    gnss_recv_buf_typedef gnss_recv_buf;
    mon_reg_task_dog( 60 * GAOZ_TICK_PERIOD_S ,(uint8_t *)GPS_MAN_NAME , TASK_SEM_YES );            /*注册任务看门狗*/
    power_man_task_reg((uint8_t * )GPS_MAN_NAME,(uint8_t *)&gnss_power_man_id ); /*注册系统电源管理*/
    log_debug_send(DEBUG_MODE,GPS_MAN_NAME ,"GNSS management task started successfully\r\n",0);
    for(;;)
    {
        mon_reset_task_dog();
        gnss_data_task_par_init();                                          /*GNSS任务参数数据初始化*/
        gnss_antenna_status_query();                                        /*GNSS天线状态获取*/
        power_man_save_state_set( gnss_power_man_id ,TASK_MODE_INIT );      /*设置当前任务的工作状态为初始值*/
        
        for( ;; )
        {
            mon_reset_task_dog();
            gnss_run_st = power_man_task_state_get( gnss_power_man_id );   /*获取任务运行的状态*/
            /************************GNSS系统处于运行状态************************/
            if(  gnss_run_st == TASK_RUN_MODE )
            {
                if( gnss_task_into_run_mode() !=   pdPASS )                 /*设置GNSS电源处理开启状态*/
                {
                    gaoz_task_sleep( 1000 );
                    continue; 
                }
                if( gnss_recv_data_queue_get( &gnss_recv_buf , GNSS_RECV_DATA_RUN_WAIT_TIME ) == pdPASS ) /*获取GNSS消息，阻塞3秒钟*/
                {
                    if( gnss_recv_buf.data == NULL )
                    {
                        continue; 
                    }
                #if( GNSS_QXWZ == 1 )
                    if( gnss_qxsdk_enable_st == GNSS_QXSDK_ENABLE )
                    {
                        if( gnss_recv_buf.len > GNSS_NMEA_DATA_LEN )
                        {
                            gnss_recv_buf.len = GNSS_NMEA_DATA_LEN;
                        }
                        memcpy((uint8_t *)gnss_nmea_data.data , gnss_recv_buf.data , gnss_recv_buf.len );
                        gnss_nmea_data.len = gnss_recv_buf.len;
                        gaoz_free_mem( (void *)gnss_recv_buf.data );
                    }
                    else //if( gnss_qxsdk_enable_st == GNSS_QXSDK_DISENABLE )
                    {
                        gnss_basic_data_filtering( &gnss_recv_buf );                   /*过滤千寻模块发送的数据*/
                        gaoz_free_mem( (void *)gnss_recv_buf.data );
                    }
                #else
                    if( gnss_recv_buf.len > GNSS_NMEA_DATA_LEN )
                    {
                        gnss_recv_buf.len = GNSS_NMEA_DATA_LEN;
                    }
                    memcpy((uint8_t *)gnss_nmea_data.data , gnss_recv_buf.data , gnss_recv_buf.len );
                    gnss_nmea_data.len = gnss_recv_buf.len;
                    gaoz_free_mem( (void *)gnss_recv_buf.data );
                #endif 
                               
                    if( gnss_data_info_parse(( uint8_t * )gnss_nmea_data.data,gnss_nmea_data.len ) == GNSS_DATA_OK )
                    { 
                        if( gnss_info_now.gnss_model_status == GPS_MODEL_POSI_OK )
                        {
                              gnss_info_now.gnss_model_status = GPS_MODEL_OK;
                        }
                        if( gnss_info_old.gnss_position_info.is_valid == 1 )          /*GNSS定位数据有效*/
                        {
                           
                            gnss_info_now.gnss_model_status = GPS_MODEL_POSI_OK;      /*模块定位成功*/
                            gnss_mileage_data_update();                               /*GNSS里程数据更新*/
                            gnss_invalid_location_reg_init();
                        }
                        else/*定位失败*/
                        {
                             
                            if( gnss_info_now.gnss_position_info.is_valid == 1 )      /*定位成功后立即清除计数*/
                            {
                                gnss_invalid_location_reg_init();
                            }
                            if( gnss_invalid_location_count() == pdPASS )
                            {
                                gnss_info_now.gnss_model_status = GPS_MODEL_POSI_ERROR;   /*模块定位失败*/
                                log_debug_printf(ERROR_MODE , GPS_MAN_NAME ,"[%s]GNSS module positioning failure,restart power (QX module restart system)" ,sys_err_infor_pointer_get( 13 ) );
                                gnss_data_driver_close();
                                gaoz_task_sleep( 3000 );
                            #if( GNSS_QXWZ == 1 )
                                if(( sys_abnormal_reset_get() == SYS_RESET_INIT ) || ( sys_abnormal_reset_get() == SYS_RESET_RUN ))
                                {
                                    sys_abnormal_reset_set( SYS_RESET_GPS );    /*模块打开电源后，1分钟没有数据输出则任务异常重新启动模块，功能仅限于千寻模块*/
                                }
                            #endif    
                                break;
                            }
                        #if 0
                            else
                            {
                                if( agnss_ephemeris_data_set() == pdPASS )
                                {
                                    log_debug_send(INFOR_MODE , GPS_MAN_NAME ,"AGNSS quick location setup successful" ,0 );
                                }
                            }
                        #endif
                        }
                        gnss_invalid_time_reg_init();
                    }
                    else    /*GPS串口有数据但是无定位*/
                    { 
                        if( gnss_invalid_time_reg_count() == pdPASS )
                        {
                            gnss_info_now.gnss_model_status = GPS_MODEL_DATA_ERROR;   /*模块定位失败*/
                            log_debug_printf(ERROR_MODE , GPS_MAN_NAME ,"[%s]GNSS module has no positioning data,restart power (QX module restart system)" ,sys_err_infor_pointer_get( 14 ) );
                            gnss_data_driver_close();
                            gaoz_task_sleep( 3000 );
                        #if( GNSS_QXWZ == 1 )
                            if(( sys_abnormal_reset_get() == SYS_RESET_INIT ) || ( sys_abnormal_reset_get() == SYS_RESET_RUN ))
                            {
                                sys_abnormal_reset_set( SYS_RESET_GPS );    /*模块打开电源后，1分钟没有数据输出则任务异常重新启动模块，功能仅限于千寻模块*/
                            }
                        #endif
                            break;
                        }
                    }
                    gnss_invalid_data_reg_init();       /*初始寄存器*/
                }
                else//----------- GPS 上电后没有正常的数据 --------------
                {   /* 打开系统电源后GPS模块 1分钟后依然没有数据认为模块故障 ,当模块为千寻模块时需要进行系统复位*/
                    if( gnss_invalid_data_count() ==  pdPASS )
                    {
                        log_debug_printf(ERROR_MODE , GPS_MAN_NAME ,"[%s]module failure,restart power (QX module restart system)" ,sys_err_infor_pointer_get( 15 ) );
                        gnss_info_now.gnss_model_status = GPS_MODEL_ERROR; 
                        gnss_data_driver_close();
                        gaoz_task_sleep(3000);       /*延时3秒钟，故障提示*/
                    #if( GNSS_QXWZ == 1 )
                        if(( sys_abnormal_reset_get() == SYS_RESET_INIT ) || ( sys_abnormal_reset_get() == SYS_RESET_RUN ))
                        {
                            sys_abnormal_reset_set( SYS_RESET_GPS );    /*模块打开电源后，1分钟没有数据输出则任务异常重新启动模块，功能仅限于千寻模块*/
                        }
                    #endif
                        break;
                    }
                }
            }
            /*******************************系统处于休眠状态************************************/
            else if( gnss_run_st == TASK_SLEEP_MODE )
            {
                if( gnss_recv_data_queue_get( &gnss_recv_buf  , GNSS_RECV_DATA_SLEEP_WAIT_TIME ) == pdPASS ) /*获取GNSS消息，阻塞3秒钟*/
                {
                    if( gnss_recv_buf.data != NULL )
                    {
                        gaoz_free_mem( (void *)gnss_recv_buf.data );
                        continue; 
                    }
                }
                else
                {
                    if( gnss_task_into_sleep_mode() == pdPASS )               /*当任务处于休眠状态时关闭GNSS电源进入长时间的睡眠状态*/
                    {
                        gnss_info_old.gnss_position_info.pos_flag = 0;        /*系统进入休眠后，GNSS数据 定位状态和速度变为0*/    
                        gnss_info_old.gnss_position_info.speed = 0;
                        gnss_info_old.gnss_position_info.sat_num =0;
                        gnss_info_old.gnss_position_info.bd_total_num_sat =0;
                        gnss_info_old.gnss_position_info.snr = 0;
                        gnss_info_old.gnss_position_info.valid_gps_total_num_sat = 0;
                        gnss_info_old.gnss_position_info.valid_bd_total_num_sat = 0;
                        gnss_info_old.gnss_position_info.gps_total_num_sat = 0;
                         
                    }
                }
            }
            /*******************************系统处于停止状态************************************/
            else if( gnss_run_st == TASK_STOP_MODE )
            {
                if( gnss_task_into_stop_mode() == pdPASS )                   /*当任务处于休眠状态时关闭GNSS电源进入长时间的停止状态*/
                {
                    gaoz_task_sleep( 1000 );
                    continue;
                }
                gaoz_task_sleep(1000);
            }
            /*******************************系统空循环状态************************************/
            else
            {
                gaoz_task_sleep(100);
            }
        }
    }
}

